Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
|
||||
|
||||
+32
-14
@@ -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,35 @@ 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 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 -C tests versionsTest'
|
||||
- env: Cmd='make gpp6install && cd contrib/pzstd && make test-pzstd && make test-pzstd32 && make test-pzstd-tsan && make test-pzstd-asan'
|
||||
install:
|
||||
- export CXX="g++-6" CC="gcc-6"
|
||||
- env: Cmd='make gcc6install && CC=gcc-6 make uasan-test-zstd-nolegacy'
|
||||
- env: Cmd='make gcc6install && CC=gcc-6 make uasan-test-zbuff'
|
||||
|
||||
# OS X Mavericks
|
||||
- env: Cmd="make gnu90build && make clean && make test && make clean && make cmakebuild && make travis-install"
|
||||
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 +47,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;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
|
||||
|
||||
The examples provided by Facebook are for non-commercial testing and evaluation
|
||||
purposes only. Facebook reserves all rights not expressly granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,10 +1,10 @@
|
||||
# ################################################################
|
||||
# Copyright (c) 2015-present, Yann Collet, Facebook, Inc.
|
||||
# Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# 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.
|
||||
# ################################################################
|
||||
|
||||
PRGDIR = programs
|
||||
@@ -29,12 +29,15 @@ default: lib-release zstd-release
|
||||
all: | allmost examples manual
|
||||
|
||||
.PHONY: allmost
|
||||
allmost: allzstd
|
||||
allmost:
|
||||
$(MAKE) -C $(ZSTDDIR) all
|
||||
$(MAKE) -C $(PRGDIR) all
|
||||
$(MAKE) -C $(TESTDIR) all
|
||||
$(MAKE) -C $(ZWRAPDIR) all
|
||||
|
||||
#skip zwrapper, can't build that on alternate architectures without the proper zlib installed
|
||||
.PHONY: allzstd
|
||||
allzstd:
|
||||
.PHONY: allarch
|
||||
allarch:
|
||||
$(MAKE) -C $(ZSTDDIR) all
|
||||
$(MAKE) -C $(PRGDIR) all
|
||||
$(MAKE) -C $(TESTDIR) all
|
||||
@@ -155,16 +158,16 @@ m32build: clean
|
||||
$(MAKE) all32
|
||||
|
||||
armbuild: clean
|
||||
CC=arm-linux-gnueabi-gcc CFLAGS="-Werror" $(MAKE) allzstd
|
||||
CC=arm-linux-gnueabi-gcc CFLAGS="-Werror" $(MAKE) allarch
|
||||
|
||||
aarch64build: clean
|
||||
CC=aarch64-linux-gnu-gcc CFLAGS="-Werror" $(MAKE) allzstd
|
||||
CC=aarch64-linux-gnu-gcc CFLAGS="-Werror" $(MAKE) allarch
|
||||
|
||||
ppcbuild: clean
|
||||
CC=powerpc-linux-gnu-gcc CLAGS="-m32 -Wno-attributes -Werror" $(MAKE) allzstd
|
||||
CC=powerpc-linux-gnu-gcc CLAGS="-m32 -Wno-attributes -Werror" $(MAKE) allarch
|
||||
|
||||
ppc64build: clean
|
||||
CC=powerpc-linux-gnu-gcc CFLAGS="-m64 -Werror" $(MAKE) allzstd
|
||||
CC=powerpc-linux-gnu-gcc CFLAGS="-m64 -Werror" $(MAKE) allarch
|
||||
|
||||
armfuzz: clean
|
||||
CC=arm-linux-gnueabi-gcc QEMU_SYS=qemu-arm-static MOREFLAGS="-static" FUZZER_FLAGS=--no-big-tests $(MAKE) -C $(TESTDIR) fuzztest
|
||||
|
||||
@@ -1,15 +1,3 @@
|
||||
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)
|
||||
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 : 32-bits build can now decode large offsets (levels 21+)
|
||||
cli : new : can split input file for dictionary training, using command -B#
|
||||
cli : fix : do not change /dev/null permissions when using command -t with root access, reported by @mike155 (#851)
|
||||
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)
|
||||
|
||||
v1.3.1
|
||||
New license : BSD + GPLv2
|
||||
perf: substantially decreased memory usage in Multi-threading mode, thanks to reports by Tino Reichardt (@mcmilk)
|
||||
|
||||
+6
-6
@@ -9,19 +9,19 @@
|
||||
- COMPILER: "gcc"
|
||||
HOST: "mingw"
|
||||
PLATFORM: "x64"
|
||||
SCRIPT: "make allzstd MOREFLAGS=-static && make -C tests test-symbols fullbench-dll fullbench-lib"
|
||||
SCRIPT: "make allarch && make -C tests test-symbols fullbench-dll fullbench-lib"
|
||||
ARTIFACT: "true"
|
||||
BUILD: "true"
|
||||
- COMPILER: "gcc"
|
||||
HOST: "mingw"
|
||||
PLATFORM: "x86"
|
||||
SCRIPT: "make allzstd MOREFLAGS=-static"
|
||||
SCRIPT: "make allarch"
|
||||
ARTIFACT: "true"
|
||||
BUILD: "true"
|
||||
- COMPILER: "clang"
|
||||
HOST: "mingw"
|
||||
PLATFORM: "x64"
|
||||
SCRIPT: "MOREFLAGS='--target=x86_64-w64-mingw32 -Werror -Wconversion -Wno-sign-conversion' make allzstd"
|
||||
SCRIPT: "MOREFLAGS='--target=x86_64-w64-mingw32 -Werror -Wconversion -Wno-sign-conversion' make allarch"
|
||||
BUILD: "true"
|
||||
|
||||
- COMPILER: "gcc"
|
||||
@@ -172,15 +172,15 @@
|
||||
- COMPILER: "gcc"
|
||||
HOST: "mingw"
|
||||
PLATFORM: "x64"
|
||||
SCRIPT: "make allzstd"
|
||||
SCRIPT: "make allarch"
|
||||
- COMPILER: "gcc"
|
||||
HOST: "mingw"
|
||||
PLATFORM: "x86"
|
||||
SCRIPT: "make allzstd"
|
||||
SCRIPT: "make allarch"
|
||||
- COMPILER: "clang"
|
||||
HOST: "mingw"
|
||||
PLATFORM: "x64"
|
||||
SCRIPT: "MOREFLAGS='--target=x86_64-w64-mingw32 -Werror -Wconversion -Wno-sign-conversion' make allzstd"
|
||||
SCRIPT: "MOREFLAGS='--target=x86_64-w64-mingw32 -Werror -Wconversion -Wno-sign-conversion' make allarch"
|
||||
|
||||
- COMPILER: "visual"
|
||||
HOST: "visual"
|
||||
|
||||
@@ -388,26 +388,6 @@
|
||||
RelativePath="..\..\..\tests\fullbench.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_fast.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_double_fast.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_lazy.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_opt.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_ldm.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
@@ -462,32 +442,12 @@
|
||||
RelativePath="..\..\..\lib\common\zstd_static.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstdmt_compress.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_compress.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_fast.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_double_fast.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_lazy.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_opt.h"
|
||||
>
|
||||
</File>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_ldm.h"
|
||||
RelativePath="..\..\..\lib\compress\zstdmt_compress.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
|
||||
@@ -400,26 +400,6 @@
|
||||
RelativePath="..\..\..\lib\decompress\zstd_decompress.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_fast.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_double_fast.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_lazy.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_opt.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_ldm.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
@@ -494,32 +474,12 @@
|
||||
RelativePath="..\..\..\lib\compress\zstdmt_compress.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\common\zstd_static.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_compress.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_fast.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_double_fast.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_lazy.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_opt.h"
|
||||
>
|
||||
</File>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_ldm.h"
|
||||
RelativePath="..\..\..\lib\common\zstd_static.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
|
||||
@@ -444,26 +444,6 @@
|
||||
RelativePath="..\..\..\lib\compress\zstdmt_compress.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_fast.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_double_fast.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_lazy.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_opt.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_ldm.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
@@ -538,6 +518,10 @@
|
||||
RelativePath="..\..\..\lib\legacy\zstd_legacy.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_opt.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\common\zstd_static.h"
|
||||
>
|
||||
@@ -574,30 +558,6 @@
|
||||
RelativePath="..\..\..\lib\compress\zstdmt_compress.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_compress.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_fast.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_double_fast.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_lazy.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_opt.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_ldm.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
|
||||
@@ -388,26 +388,6 @@
|
||||
RelativePath="..\..\..\lib\compress\zstd_compress.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_fast.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_double_fast.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_lazy.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_opt.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_ldm.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\decompress\zstd_decompress.c"
|
||||
>
|
||||
@@ -514,32 +494,12 @@
|
||||
RelativePath="..\..\..\lib\legacy\zstd_legacy.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstdmt_compress.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_compress.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_fast.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_double_fast.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_lazy.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_opt.h"
|
||||
>
|
||||
</File>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\compress\zstd_ldm.h"
|
||||
RelativePath="..\..\..\lib\compress\zstdmt_compress.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
||||
@@ -166,11 +166,6 @@
|
||||
<ClCompile Include="..\..\..\lib\compress\huf_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstdmt_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_fast.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_double_fast.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_lazy.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_opt.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_ldm.c" />
|
||||
<ClCompile Include="..\..\..\lib\decompress\huf_decompress.c" />
|
||||
<ClCompile Include="..\..\..\lib\decompress\zstd_decompress.c" />
|
||||
<ClCompile Include="..\..\..\programs\datagen.c" />
|
||||
@@ -185,12 +180,7 @@
|
||||
<ClInclude Include="..\..\..\lib\common\pool.h" />
|
||||
<ClInclude Include="..\..\..\lib\common\threading.h" />
|
||||
<ClInclude Include="..\..\..\lib\common\xxhash.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_compress.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_fast.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_double_fast.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_lazy.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_opt.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_ldm.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstdmt_compress.h" />
|
||||
<ClInclude Include="..\..\..\lib\legacy\zstd_legacy.h" />
|
||||
<ClInclude Include="..\..\..\programs\datagen.h" />
|
||||
|
||||
@@ -165,11 +165,6 @@
|
||||
<ClCompile Include="..\..\..\lib\compress\fse_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\huf_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_fast.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_double_fast.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_lazy.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_opt.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_ldm.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstdmt_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\decompress\huf_decompress.c" />
|
||||
<ClCompile Include="..\..\..\lib\decompress\zstd_decompress.c" />
|
||||
@@ -188,12 +183,7 @@
|
||||
<ClInclude Include="..\..\..\lib\common\zstd_internal.h" />
|
||||
<ClInclude Include="..\..\..\lib\common\zstd_errors.h" />
|
||||
<ClInclude Include="..\..\..\lib\zstd.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_compress.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_fast.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_double_fast.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_lazy.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_opt.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_ldm.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstdmt_compress.h" />
|
||||
<ClInclude Include="..\..\..\lib\dictBuilder\divsufsort.h" />
|
||||
<ClInclude Include="..\..\..\lib\dictBuilder\zdict.h" />
|
||||
|
||||
@@ -29,11 +29,6 @@
|
||||
<ClCompile Include="..\..\..\lib\compress\fse_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\huf_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_fast.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_double_fast.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_lazy.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_opt.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_ldm.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstdmt_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\decompress\huf_decompress.c" />
|
||||
<ClCompile Include="..\..\..\lib\decompress\zstd_decompress.c" />
|
||||
@@ -72,12 +67,7 @@
|
||||
<ClInclude Include="..\..\..\lib\legacy\zstd_v07.h" />
|
||||
<ClInclude Include="..\..\..\lib\zstd.h" />
|
||||
<ClInclude Include="..\..\..\lib\common\zstd_internal.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_compress.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_fast.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_double_fast.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_lazy.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_opt.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_ldm.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstdmt_compress.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -29,11 +29,6 @@
|
||||
<ClCompile Include="..\..\..\lib\compress\fse_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\huf_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_fast.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_double_fast.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_lazy.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_opt.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_ldm.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstdmt_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\decompress\huf_decompress.c" />
|
||||
<ClCompile Include="..\..\..\lib\decompress\zstd_decompress.c" />
|
||||
@@ -72,12 +67,7 @@
|
||||
<ClInclude Include="..\..\..\lib\legacy\zstd_v07.h" />
|
||||
<ClInclude Include="..\..\..\lib\zstd.h" />
|
||||
<ClInclude Include="..\..\..\lib\common\zstd_internal.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_compress.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_fast.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_double_fast.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_lazy.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_opt.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_ldm.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstdmt_compress.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
|
||||
@@ -30,11 +30,6 @@
|
||||
<ClCompile Include="..\..\..\lib\compress\huf_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstdmt_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_compress.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_fast.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_double_fast.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_lazy.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_opt.c" />
|
||||
<ClCompile Include="..\..\..\lib\compress\zstd_ldm.c" />
|
||||
<ClCompile Include="..\..\..\lib\decompress\huf_decompress.c" />
|
||||
<ClCompile Include="..\..\..\lib\decompress\zstd_decompress.c" />
|
||||
<ClCompile Include="..\..\..\lib\dictBuilder\cover.c" />
|
||||
@@ -65,12 +60,7 @@
|
||||
<ClInclude Include="..\..\..\lib\zstd.h" />
|
||||
<ClInclude Include="..\..\..\lib\common\zstd_internal.h" />
|
||||
<ClInclude Include="..\..\..\lib\common\zstd_errors.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_compress.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_fast.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_double_fast.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_lazy.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_opt.h" />
|
||||
<ClInclude Include="..\..\..\lib\compress\zstd_ldm.h" />
|
||||
<ClInclude Include="..\..\..\lib\legacy\zstd_legacy.h" />
|
||||
<ClInclude Include="..\..\..\lib\legacy\zstd_v01.h" />
|
||||
<ClInclude Include="..\..\..\lib\legacy\zstd_v02.h" />
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
# Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# 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.
|
||||
# ################################################################
|
||||
|
||||
PROJECT(zstd)
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
# ################################################################
|
||||
# Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
# * Copyright (c) 2015-present, Yann Collet, 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 can contact the author at :
|
||||
# - zstd homepage : http://www.zstd.net/
|
||||
# ################################################################
|
||||
|
||||
PROJECT(contrib)
|
||||
|
||||
ADD_SUBDIRECTORY(pzstd)
|
||||
ADD_SUBDIRECTORY(gen_html)
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
# ################################################################
|
||||
# Copyright (c) 2015-present, Yann Collet, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
# * Copyright (c) 2015-present, Yann Collet, 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 can contact the author at :
|
||||
# - zstd homepage : http://www.zstd.net/
|
||||
# ################################################################
|
||||
|
||||
PROJECT(gen_html)
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
# ################################################################
|
||||
# Copyright (c) 2016-present, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
# * Copyright (c) 2015-present, Yann Collet, 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 can contact the author at :
|
||||
# - zstd homepage : http://www.zstd.net/
|
||||
# ################################################################
|
||||
|
||||
PROJECT(pzstd)
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
# ################################################################
|
||||
# Copyright (c) 2015-present, Yann Collet, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
# * Copyright (c) 2014-present, Yann Collet, 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 can contact the author at :
|
||||
# - zstd homepage : http://www.zstd.net/
|
||||
# ################################################################
|
||||
|
||||
PROJECT(libzstd)
|
||||
@@ -38,11 +41,6 @@ SET(Sources
|
||||
${LIBRARY_DIR}/compress/huf_compress.c
|
||||
${LIBRARY_DIR}/compress/zstd_compress.c
|
||||
${LIBRARY_DIR}/compress/zstdmt_compress.c
|
||||
${LIBRARY_DIR}/compress/zstd_fast.c
|
||||
${LIBRARY_DIR}/compress/zstd_double_fast.c
|
||||
${LIBRARY_DIR}/compress/zstd_lazy.c
|
||||
${LIBRARY_DIR}/compress/zstd_opt.c
|
||||
${LIBRARY_DIR}/compress/zstd_ldm.c
|
||||
${LIBRARY_DIR}/decompress/huf_decompress.c
|
||||
${LIBRARY_DIR}/decompress/zstd_decompress.c
|
||||
${LIBRARY_DIR}/dictBuilder/cover.c
|
||||
@@ -63,12 +61,6 @@ SET(Headers
|
||||
${LIBRARY_DIR}/common/huf.h
|
||||
${LIBRARY_DIR}/common/mem.h
|
||||
${LIBRARY_DIR}/common/zstd_internal.h
|
||||
${LIBRARY_DIR}/compress/zstd_compress.h
|
||||
${LIBRARY_DIR}/compress/zstd_fast.h
|
||||
${LIBRARY_DIR}/compress/zstd_double_fast.h
|
||||
${LIBRARY_DIR}/compress/zstd_lazy.h
|
||||
${LIBRARY_DIR}/compress/zstd_opt.h
|
||||
${LIBRARY_DIR}/compress/zstd_ldm.h
|
||||
${LIBRARY_DIR}/compress/zstdmt_compress.h
|
||||
${LIBRARY_DIR}/dictBuilder/zdict.h
|
||||
${LIBRARY_DIR}/deprecated/zbuff.h)
|
||||
@@ -159,10 +151,10 @@ IF (UNIX)
|
||||
ENDIF (UNIX)
|
||||
|
||||
# install target
|
||||
INSTALL(FILES
|
||||
${LIBRARY_DIR}/zstd.h
|
||||
${LIBRARY_DIR}/deprecated/zbuff.h
|
||||
${LIBRARY_DIR}/dictBuilder/zdict.h
|
||||
INSTALL(FILES
|
||||
${LIBRARY_DIR}/zstd.h
|
||||
${LIBRARY_DIR}/deprecated/zbuff.h
|
||||
${LIBRARY_DIR}/dictBuilder/zdict.h
|
||||
${LIBRARY_DIR}/common/zstd_errors.h
|
||||
DESTINATION "include")
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
# ################################################################
|
||||
# Copyright (c) 2015-present, Yann Collet, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
# * Copyright (c) 2015-present, Yann Collet, 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 can contact the author at :
|
||||
# - zstd homepage : http://www.zstd.net/
|
||||
# ################################################################
|
||||
|
||||
PROJECT(programs)
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ dependencies:
|
||||
test:
|
||||
override:
|
||||
- ? |
|
||||
if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then cc -v; make all && make clean && make -C lib libzstd-nomt && make clean; fi &&
|
||||
if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then cc -v; make all && make clean; fi &&
|
||||
if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make gnu90build && make clean; fi
|
||||
:
|
||||
parallel: true
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h> /* fprintf */
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# ################################################################
|
||||
# ##########################################################################
|
||||
# Copyright (c) 2016-present, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# ################################################################
|
||||
# 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.
|
||||
# ##########################################################################
|
||||
|
||||
CFLAGS ?= -O3
|
||||
CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wstrict-aliasing=1 -Wswitch-enum -Wno-comment
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
* Copyright (c) 2016-present, Przemyslaw Skibinski, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From 2b29ec569f8438a0307debd29873859ca6d407fc Mon Sep 17 00:00:00 2001
|
||||
From b7f044163968d724be55bf4841fd80babe036dc2 Mon Sep 17 00:00:00 2001
|
||||
From: Nick Terrell <terrelln@fb.com>
|
||||
Date: Mon, 17 Jul 2017 17:08:19 -0700
|
||||
Subject: [PATCH v5 2/5] lib: Add zstd modules
|
||||
@@ -121,26 +121,26 @@ v4 -> v5:
|
||||
- Fix rare compression bug from upstream commit 308047eb5d
|
||||
- Fix bug introduced in v3 when working around the gcc-7 bug
|
||||
|
||||
include/linux/zstd.h | 1155 +++++++++++++++
|
||||
include/linux/zstd.h | 1157 +++++++++++++++
|
||||
lib/Kconfig | 8 +
|
||||
lib/Makefile | 2 +
|
||||
lib/zstd/Makefile | 18 +
|
||||
lib/zstd/bitstream.h | 374 +++++
|
||||
lib/zstd/compress.c | 3482 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
lib/zstd/decompress.c | 2526 ++++++++++++++++++++++++++++++++
|
||||
lib/zstd/compress.c | 3484 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
lib/zstd/decompress.c | 2528 ++++++++++++++++++++++++++++++++
|
||||
lib/zstd/entropy_common.c | 243 ++++
|
||||
lib/zstd/error_private.h | 51 +
|
||||
lib/zstd/error_private.h | 53 +
|
||||
lib/zstd/fse.h | 575 ++++++++
|
||||
lib/zstd/fse_compress.c | 795 +++++++++++
|
||||
lib/zstd/fse_decompress.c | 332 +++++
|
||||
lib/zstd/huf.h | 212 +++
|
||||
lib/zstd/huf_compress.c | 770 ++++++++++
|
||||
lib/zstd/huf_decompress.c | 960 +++++++++++++
|
||||
lib/zstd/mem.h | 149 ++
|
||||
lib/zstd/zstd_common.c | 73 +
|
||||
lib/zstd/zstd_internal.h | 261 ++++
|
||||
lib/zstd/zstd_opt.h | 1012 +++++++++++++
|
||||
19 files changed, 12998 insertions(+)
|
||||
lib/zstd/mem.h | 151 ++
|
||||
lib/zstd/zstd_common.c | 75 +
|
||||
lib/zstd/zstd_internal.h | 263 ++++
|
||||
lib/zstd/zstd_opt.h | 1014 +++++++++++++
|
||||
19 files changed, 13014 insertions(+)
|
||||
create mode 100644 include/linux/zstd.h
|
||||
create mode 100644 lib/zstd/Makefile
|
||||
create mode 100644 lib/zstd/bitstream.h
|
||||
@@ -161,16 +161,18 @@ v4 -> v5:
|
||||
|
||||
diff --git a/include/linux/zstd.h b/include/linux/zstd.h
|
||||
new file mode 100644
|
||||
index 0000000..305efd0
|
||||
index 0000000..249575e
|
||||
--- /dev/null
|
||||
+++ b/include/linux/zstd.h
|
||||
@@ -0,0 +1,1155 @@
|
||||
@@ -0,0 +1,1157 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2016-present, Yann Collet, 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 https://github.com/facebook/zstd.
|
||||
+ * An additional grant of patent rights can be found in the PATENTS file in the
|
||||
+ * same directory.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it under
|
||||
+ * the terms of the GNU General Public License version 2 as published by the
|
||||
@@ -1758,16 +1760,18 @@ index 0000000..a826b99
|
||||
+#endif /* BITSTREAM_H_MODULE */
|
||||
diff --git a/lib/zstd/compress.c b/lib/zstd/compress.c
|
||||
new file mode 100644
|
||||
index 0000000..ff18ae6
|
||||
index 0000000..f9166cf
|
||||
--- /dev/null
|
||||
+++ b/lib/zstd/compress.c
|
||||
@@ -0,0 +1,3482 @@
|
||||
@@ -0,0 +1,3484 @@
|
||||
+/**
|
||||
+ * Copyright (c) 2016-present, Yann Collet, 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 https://github.com/facebook/zstd.
|
||||
+ * An additional grant of patent rights can be found in the PATENTS file in the
|
||||
+ * same directory.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it under
|
||||
+ * the terms of the GNU General Public License version 2 as published by the
|
||||
@@ -5246,16 +5250,18 @@ index 0000000..ff18ae6
|
||||
+MODULE_DESCRIPTION("Zstd Compressor");
|
||||
diff --git a/lib/zstd/decompress.c b/lib/zstd/decompress.c
|
||||
new file mode 100644
|
||||
index 0000000..72df4828
|
||||
index 0000000..b178467
|
||||
--- /dev/null
|
||||
+++ b/lib/zstd/decompress.c
|
||||
@@ -0,0 +1,2526 @@
|
||||
@@ -0,0 +1,2528 @@
|
||||
+/**
|
||||
+ * Copyright (c) 2016-present, Yann Collet, 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 https://github.com/facebook/zstd.
|
||||
+ * An additional grant of patent rights can be found in the PATENTS file in the
|
||||
+ * same directory.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it under
|
||||
+ * the terms of the GNU General Public License version 2 as published by the
|
||||
@@ -8027,16 +8033,18 @@ index 0000000..2b0a643
|
||||
+}
|
||||
diff --git a/lib/zstd/error_private.h b/lib/zstd/error_private.h
|
||||
new file mode 100644
|
||||
index 0000000..2062ff0
|
||||
index 0000000..1a60b31
|
||||
--- /dev/null
|
||||
+++ b/lib/zstd/error_private.h
|
||||
@@ -0,0 +1,51 @@
|
||||
@@ -0,0 +1,53 @@
|
||||
+/**
|
||||
+ * Copyright (c) 2016-present, Yann Collet, 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 https://github.com/facebook/zstd.
|
||||
+ * An additional grant of patent rights can be found in the PATENTS file in the
|
||||
+ * same directory.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it under
|
||||
+ * the terms of the GNU General Public License version 2 as published by the
|
||||
@@ -11764,16 +11772,18 @@ index 0000000..6526482
|
||||
+}
|
||||
diff --git a/lib/zstd/mem.h b/lib/zstd/mem.h
|
||||
new file mode 100644
|
||||
index 0000000..42a697b
|
||||
index 0000000..3a0f34c
|
||||
--- /dev/null
|
||||
+++ b/lib/zstd/mem.h
|
||||
@@ -0,0 +1,149 @@
|
||||
@@ -0,0 +1,151 @@
|
||||
+/**
|
||||
+ * Copyright (c) 2016-present, Yann Collet, 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 https://github.com/facebook/zstd.
|
||||
+ * An additional grant of patent rights can be found in the PATENTS file in the
|
||||
+ * same directory.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it under
|
||||
+ * the terms of the GNU General Public License version 2 as published by the
|
||||
@@ -11919,16 +11929,18 @@ index 0000000..42a697b
|
||||
+#endif /* MEM_H_MODULE */
|
||||
diff --git a/lib/zstd/zstd_common.c b/lib/zstd/zstd_common.c
|
||||
new file mode 100644
|
||||
index 0000000..e5f06d7
|
||||
index 0000000..a282624
|
||||
--- /dev/null
|
||||
+++ b/lib/zstd/zstd_common.c
|
||||
@@ -0,0 +1,73 @@
|
||||
@@ -0,0 +1,75 @@
|
||||
+/**
|
||||
+ * Copyright (c) 2016-present, Yann Collet, 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 https://github.com/facebook/zstd.
|
||||
+ * An additional grant of patent rights can be found in the PATENTS file in the
|
||||
+ * same directory.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it under
|
||||
+ * the terms of the GNU General Public License version 2 as published by the
|
||||
@@ -11998,16 +12010,18 @@ index 0000000..e5f06d7
|
||||
+}
|
||||
diff --git a/lib/zstd/zstd_internal.h b/lib/zstd/zstd_internal.h
|
||||
new file mode 100644
|
||||
index 0000000..a0fb83e
|
||||
index 0000000..1a79fab
|
||||
--- /dev/null
|
||||
+++ b/lib/zstd/zstd_internal.h
|
||||
@@ -0,0 +1,261 @@
|
||||
@@ -0,0 +1,263 @@
|
||||
+/**
|
||||
+ * Copyright (c) 2016-present, Yann Collet, 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 https://github.com/facebook/zstd.
|
||||
+ * An additional grant of patent rights can be found in the PATENTS file in the
|
||||
+ * same directory.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it under
|
||||
+ * the terms of the GNU General Public License version 2 as published by the
|
||||
@@ -12265,16 +12279,18 @@ index 0000000..a0fb83e
|
||||
+#endif /* ZSTD_CCOMMON_H_MODULE */
|
||||
diff --git a/lib/zstd/zstd_opt.h b/lib/zstd/zstd_opt.h
|
||||
new file mode 100644
|
||||
index 0000000..ecdd725
|
||||
index 0000000..55e1b4c
|
||||
--- /dev/null
|
||||
+++ b/lib/zstd/zstd_opt.h
|
||||
@@ -0,0 +1,1012 @@
|
||||
@@ -0,0 +1,1014 @@
|
||||
+/**
|
||||
+ * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, 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 https://github.com/facebook/zstd.
|
||||
+ * An additional grant of patent rights can be found in the PATENTS file in the
|
||||
+ * same directory.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it under
|
||||
+ * the terms of the GNU General Public License version 2 as published by the
|
||||
@@ -13282,4 +13298,4 @@ index 0000000..ecdd725
|
||||
+
|
||||
+#endif /* ZSTD_OPT_H_91842398743 */
|
||||
--
|
||||
2.9.5
|
||||
2.9.3
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of https://github.com/facebook/zstd.
|
||||
* An additional grant of patent rights can be found in the PATENTS file in the
|
||||
* same directory.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of https://github.com/facebook/zstd.
|
||||
* An additional grant of patent rights can be found in the PATENTS file in the
|
||||
* same directory.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of https://github.com/facebook/zstd.
|
||||
* An additional grant of patent rights can be found in the PATENTS file in the
|
||||
* same directory.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of https://github.com/facebook/zstd.
|
||||
* An additional grant of patent rights can be found in the PATENTS file in the
|
||||
* same directory.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of https://github.com/facebook/zstd.
|
||||
* An additional grant of patent rights can be found in the PATENTS file in the
|
||||
* same directory.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of https://github.com/facebook/zstd.
|
||||
* An additional grant of patent rights can be found in the PATENTS file in the
|
||||
* same directory.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of https://github.com/facebook/zstd.
|
||||
* An additional grant of patent rights can be found in the PATENTS file in the
|
||||
* same directory.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of https://github.com/facebook/zstd.
|
||||
* An additional grant of patent rights can be found in the PATENTS file in the
|
||||
* same directory.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -2,13 +2,19 @@
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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 program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. This program is dual-licensed; you may select
|
||||
* either version 2 of the GNU General Public License ("GPL") or BSD license
|
||||
* ("BSD").
|
||||
*/
|
||||
|
||||
/* DO_XXH should be 32 or 64 for xxh32 and xxh64 respectively */
|
||||
#define DO_XXH 0
|
||||
#define DO_XXH 0
|
||||
/* DO_CRC should be 0 or 1 */
|
||||
#define DO_CRC 0
|
||||
/* Buffer size */
|
||||
|
||||
@@ -2,9 +2,15 @@
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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 program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. This program is dual-licensed; you may select
|
||||
* either version 2 of the GNU General Public License ("GPL") or BSD license
|
||||
* ("BSD").
|
||||
*/
|
||||
|
||||
/* Compression level or 0 to disable */
|
||||
|
||||
@@ -2,9 +2,15 @@
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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 program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. This program is dual-licensed; you may select
|
||||
* either version 2 of the GNU General Public License ("GPL") or BSD license
|
||||
* ("BSD").
|
||||
*/
|
||||
|
||||
/* Compression level or 0 to disable */
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# ################################################################
|
||||
# Copyright (c) 2017-present, Facebook, Inc.
|
||||
# Copyright (c) 2016-present, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# 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 Makefile presumes libzstd is installed, using `sudo make install`
|
||||
@@ -25,8 +25,8 @@ LDFLAGS += -lzstd
|
||||
|
||||
default: all
|
||||
|
||||
all: ldm
|
||||
|
||||
all: ldm
|
||||
|
||||
ldm: ldm_common.c ldm.c main.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||
|
||||
@@ -34,3 +34,4 @@ clean:
|
||||
@rm -f core *.o tmp* result* *.ldm *.ldm.dec \
|
||||
ldm
|
||||
@echo Cleaning completed
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# ################################################################
|
||||
# ##########################################################################
|
||||
# Copyright (c) 2016-present, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# ################################################################
|
||||
# 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.
|
||||
# ##########################################################################
|
||||
|
||||
# Standard variables for installation
|
||||
DESTDIR ?=
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#include "Options.h"
|
||||
#include "util.h"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#include "Pzstd.h"
|
||||
#include "SkippableFrame.h"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#include "SkippableFrame.h"
|
||||
#include "mem.h"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#include "ErrorHolder.h"
|
||||
#include "Options.h"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#include "Options.h"
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#include "Pzstd.h"
|
||||
extern "C" {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
extern "C" {
|
||||
#include "datagen.h"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#include "utils/Buffer.h"
|
||||
#include "utils/Range.h"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#include "utils/Range.h"
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#include "utils/ResourcePool.h"
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#include "utils/ScopeGuard.h"
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#include "utils/ThreadPool.h"
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
#include "utils/Buffer.h"
|
||||
#include "utils/WorkQueue.h"
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
# Copyright (c) 2017-present, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# 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 Makefile presumes libzstd is built, using `make` in / or /lib/
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
/**
|
||||
* Copyright 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE-examples file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include <stdlib.h> // malloc, free, exit, atoi
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
/**
|
||||
* Copyright 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE-examples file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
/**
|
||||
* Copyright 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE-examples file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include <stdlib.h> // malloc, free, exit, atoi
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
/**
|
||||
* Copyright 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE-examples file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/// Zstandard educational decoder implementation
|
||||
@@ -1289,7 +1289,7 @@ static void execute_sequences(frame_context_t *const ctx, ostream_t *const out,
|
||||
// Copy any leftover literals
|
||||
{
|
||||
size_t len = IO_istream_len(&litstream);
|
||||
copy_literals(len, &litstream, out);
|
||||
copy_literals(len, &litstream, out);
|
||||
total_output += len;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/******* EXPOSED TYPES ********************************************************/
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 71 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 27 KiB |
+71
-165
@@ -27,8 +27,7 @@
|
||||
<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">Block functions</a></li>
|
||||
</ol>
|
||||
<hr>
|
||||
<a name="Chapter1"></a><h2>Introduction</h2><pre>
|
||||
@@ -403,29 +402,25 @@ size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
|
||||
</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_advanced(ZSTD_compressionParameters cParams);
|
||||
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_advanced() can provide a tighter estimation.
|
||||
ZSTD_estimateCCtxSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||
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_advanced(ZSTD_compressionParameters cParams);
|
||||
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_advanced() can provide a tighter estimation.
|
||||
ZSTD_estimateCStreamSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||
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,
|
||||
@@ -435,18 +430,12 @@ size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
|
||||
In this case, get total size by adding ZSTD_estimate?DictSize
|
||||
</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_dictLoadMethod_e;
|
||||
</b></pre><BR>
|
||||
<pre><b>size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel);
|
||||
size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod);
|
||||
size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod);
|
||||
size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference);
|
||||
size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference);
|
||||
</b><p> ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict().
|
||||
ZSTD_estimateCStreamSize_advanced_usingCParams() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced().
|
||||
Note : dictionary created by reference using ZSTD_dlm_byRef are smaller
|
||||
|
||||
ZSTD_estimateCStreamSize_advanced() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced().
|
||||
Note : dictionary created "byReference" are smaller
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter14"></a><h2>Advanced compression functions</h2><pre></pre>
|
||||
@@ -472,6 +461,16 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>typedef enum {
|
||||
ZSTD_p_forceWindow, </b>/* Force back-references to remain < windowSize, even when referencing Dictionary content (default:0) */<b>
|
||||
ZSTD_p_forceRawDict </b>/* Force loading dictionary in "content-only" mode (no header analysis) */<b>
|
||||
} ZSTD_CCtxParameter;
|
||||
</b></pre><BR>
|
||||
<pre><b>size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value);
|
||||
</b><p> Set advanced parameters, selected through enum ZSTD_CCtxParameter
|
||||
@result : 0, or an error code (which can be tested with ZSTD_isError())
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel);
|
||||
</b><p> Create a digested dictionary for compression
|
||||
Dictionary content is simply referenced, and therefore stays in dictBuffer.
|
||||
@@ -484,8 +483,7 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
|
||||
} ZSTD_dictMode_e;
|
||||
</b></pre><BR>
|
||||
<pre><b>ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize,
|
||||
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||
ZSTD_dictMode_e dictMode,
|
||||
unsigned byReference, ZSTD_dictMode_e dictMode,
|
||||
ZSTD_compressionParameters cParams,
|
||||
ZSTD_customMem customMem);
|
||||
</b><p> Create a ZSTD_CDict using external alloc and free, and customized compression parameters
|
||||
@@ -494,7 +492,7 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
|
||||
<pre><b>ZSTD_CDict* ZSTD_initStaticCDict(
|
||||
void* workspace, size_t workspaceSize,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode,
|
||||
unsigned byReference, ZSTD_dictMode_e dictMode,
|
||||
ZSTD_compressionParameters cParams);
|
||||
</b><p> Generate a digested dictionary in provided memory area.
|
||||
workspace: The memory area to emplace the dictionary into.
|
||||
@@ -582,14 +580,13 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
|
||||
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||
ZSTD_customMem customMem);
|
||||
unsigned byReference, ZSTD_customMem customMem);
|
||||
</b><p> Create a ZSTD_DDict using external alloc and free, optionally by reference
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSize,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictLoadMethod_e dictLoadMethod);
|
||||
unsigned byReference);
|
||||
</b><p> Generate a digested dictionary in provided memory area.
|
||||
workspace: The memory area to emplace the dictionary into.
|
||||
Provided pointer must 8-bytes aligned.
|
||||
@@ -631,9 +628,9 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
|
||||
<h3>Advanced Streaming compression functions</h3><pre></pre><b><pre>ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem);
|
||||
ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); </b>/**< same as ZSTD_initStaticCCtx() */<b>
|
||||
size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); </b>/**< pledgedSrcSize must be correct, a size of 0 means unknown. for a frame size of 0 use initCStream_advanced */<b>
|
||||
size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); </b>/**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. Note: dict is loaded with ZSTD_dm_auto (treated as a full zstd dictionary if it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.*/<b>
|
||||
size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); </b>/**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. */<b>
|
||||
size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize,
|
||||
ZSTD_parameters params, unsigned long long pledgedSrcSize); </b>/**< pledgedSrcSize is optional and can be 0 (meaning unknown). note: if the contentSizeFlag is set, pledgedSrcSize == 0 means the source size is actually 0. dict is loaded with ZSTD_dm_auto and ZSTD_dlm_byCopy. */<b>
|
||||
ZSTD_parameters params, unsigned long long pledgedSrcSize); </b>/**< pledgedSrcSize is optional and can be 0 (meaning unknown). note: if the contentSizeFlag is set, pledgedSrcSize == 0 means the source size is actually 0 */<b>
|
||||
size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); </b>/**< note : cdict will just be referenced, and must outlive compression session */<b>
|
||||
size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize); </b>/**< same as ZSTD_initCStream_usingCDict(), with control over frame parameters */<b>
|
||||
</pre></b><BR>
|
||||
@@ -703,53 +700,40 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned lo
|
||||
A ZSTD_DCtx object can be re-used multiple times.
|
||||
|
||||
First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader().
|
||||
It fills a ZSTD_frameHeader structure with important information to correctly decode the frame,
|
||||
such as minimum rolling buffer size to allocate to decompress data (`windowSize`),
|
||||
and the dictionary ID in use.
|
||||
(Note : content size is optional, it may not be present. 0 means : content size unknown).
|
||||
Note that these values could be wrong, either because of data malformation, or because an attacker is spoofing deliberate false information.
|
||||
As a consequence, check that values remain within valid application range, especially `windowSize`, before allocation.
|
||||
Each application can set its own limit, depending on local restrictions.
|
||||
For extended interoperability, it is recommended to support windowSize of at least 8 MB.
|
||||
Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough.
|
||||
Data fragment must be large enough to ensure successful decoding.
|
||||
`ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough.
|
||||
`ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough.
|
||||
@result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled.
|
||||
>0 : `srcSize` is too small, please provide at least @result bytes on next attempt.
|
||||
errorCode, which can be tested using ZSTD_isError().
|
||||
|
||||
It fills a ZSTD_frameHeader structure with important information to correctly decode the frame,
|
||||
such as the dictionary ID, content size, or maximum back-reference distance (`windowSize`).
|
||||
Note that these values could be wrong, either because of data corruption, or because a 3rd party deliberately spoofs false information.
|
||||
As a consequence, check that values remain within valid application range.
|
||||
For example, do not allocate memory blindly, check that `windowSize` is within expectation.
|
||||
Each application can set its own limits, depending on local restrictions.
|
||||
For extended interoperability, it is recommended to support `windowSize` of at least 8 MB.
|
||||
|
||||
ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize` bytes.
|
||||
ZSTD_decompressContinue() is very sensitive to contiguity,
|
||||
if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place,
|
||||
or that previous contiguous segment is large enough to properly handle maximum back-reference distance.
|
||||
There are multiple ways to guarantee this condition.
|
||||
|
||||
The most memory efficient way is to use a round buffer of sufficient size.
|
||||
Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(),
|
||||
which can @return an error code if required value is too large for current system (in 32-bits mode).
|
||||
In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one,
|
||||
up to the moment there is not enough room left in the buffer to guarantee decoding another full block,
|
||||
which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`.
|
||||
At which point, decoding can resume from the beginning of the buffer.
|
||||
Note that already decoded data stored in the buffer should be flushed before being overwritten.
|
||||
|
||||
There are alternatives possible, for example using two or more buffers of size `windowSize` each, though they consume more memory.
|
||||
|
||||
Finally, if you control the compression process, you can also ignore all buffer size rules,
|
||||
as long as the encoder and decoder progress in "lock-step",
|
||||
aka use exactly the same buffer sizes, break contiguity at the same place, etc.
|
||||
|
||||
Once buffers are setup, start decompression, with ZSTD_decompressBegin().
|
||||
Start decompression, with ZSTD_decompressBegin().
|
||||
If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict().
|
||||
Alternatively, you can copy a prepared context, using ZSTD_copyDCtx().
|
||||
|
||||
Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively.
|
||||
ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue().
|
||||
ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail.
|
||||
|
||||
@result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity).
|
||||
It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item.
|
||||
@result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity).
|
||||
It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some metadata item.
|
||||
It can also be an error code, which can be tested with ZSTD_isError().
|
||||
|
||||
ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize`.
|
||||
They should preferably be located contiguously, prior to current block.
|
||||
Alternatively, a round buffer of sufficient size is also possible. Sufficient size is determined by frame parameters.
|
||||
ZSTD_decompressContinue() is very sensitive to contiguity,
|
||||
if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place,
|
||||
or that previous contiguous segment is large enough to properly handle maximum back-reference.
|
||||
|
||||
A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero.
|
||||
Context can then be reset to start a new decompression.
|
||||
|
||||
@@ -759,27 +743,32 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned lo
|
||||
== Special case : skippable frames
|
||||
|
||||
Skippable frames allow integration of user-defined data into a flow of concatenated frames.
|
||||
Skippable frames will be ignored (skipped) by decompressor.
|
||||
The format of skippable frames is as follows :
|
||||
Skippable frames will be ignored (skipped) by a decompressor. The format of skippable frames is as follows :
|
||||
a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F
|
||||
b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits
|
||||
c) Frame Content - any content (User Data) of length equal to Frame Size
|
||||
For skippable frames ZSTD_getFrameHeader() returns zfhPtr->frameType==ZSTD_skippableFrame.
|
||||
For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content.
|
||||
For skippable frames ZSTD_decompressContinue() always returns 0.
|
||||
For skippable frames ZSTD_getFrameHeader() returns fparamsPtr->windowLog==0 what means that a frame is skippable.
|
||||
Note : If fparamsPtr->frameContentSize==0, it is ambiguous: the frame might actually be a Zstd encoded frame with no content.
|
||||
For purposes of decompression, it is valid in both cases to skip the frame using
|
||||
ZSTD_findFrameCompressedSize to find its size in bytes.
|
||||
It also returns Frame Size as fparamsPtr->frameContentSize.
|
||||
<BR></pre>
|
||||
|
||||
<h3>Buffer-less streaming decompression functions</h3><pre></pre><b><pre>typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e;
|
||||
typedef struct {
|
||||
unsigned long long frameContentSize; </b>/* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */<b>
|
||||
unsigned long long frameContentSize; </b>/* ZSTD_CONTENTSIZE_UNKNOWN means this field is not available. 0 means "empty" */<b>
|
||||
unsigned long long windowSize; </b>/* can be very large, up to <= frameContentSize */<b>
|
||||
unsigned blockSizeMax;
|
||||
ZSTD_frameType_e frameType; </b>/* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */<b>
|
||||
unsigned headerSize;
|
||||
unsigned dictID;
|
||||
unsigned checksumFlag;
|
||||
} ZSTD_frameHeader;
|
||||
size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); </b>/**< doesn't consume input */<b>
|
||||
size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); </b>/**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */<b>
|
||||
size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx);
|
||||
size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
|
||||
size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
|
||||
void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx);
|
||||
</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>
|
||||
@@ -830,6 +819,12 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
|
||||
ZSTD_p_checksumFlag, </b>/* A 32-bits checksum of content is written at end of frame (default:0) */<b>
|
||||
ZSTD_p_dictIDFlag, </b>/* When applicable, dictID of dictionary is provided in frame header (default:1) */<b>
|
||||
|
||||
</b>/* dictionary parameters (must be set before ZSTD_CCtx_loadDictionary) */<b>
|
||||
ZSTD_p_dictMode=300, </b>/* Select how dictionary content must be interpreted. Value must be from type ZSTD_dictMode_e.<b>
|
||||
* default : 0==auto : dictionary will be "full" if it respects specification, otherwise it will be "rawContent" */
|
||||
ZSTD_p_refDictContent, </b>/* Dictionary content will be referenced, instead of copied (default:0==byCopy).<b>
|
||||
* It requires that dictionary buffer outlives its users */
|
||||
|
||||
</b>/* multi-threading parameters */<b>
|
||||
ZSTD_p_nbThreads=400, </b>/* Select how many threads a compression job can spawn (default:1)<b>
|
||||
* More threads improve speed, but also increase memory usage.
|
||||
@@ -845,35 +840,6 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
|
||||
</b>/* advanced parameters - may not remain available after API update */<b>
|
||||
ZSTD_p_forceMaxWindow=1100, </b>/* Force back-reference distances to remain < windowSize,<b>
|
||||
* even when referencing into Dictionary content (default:0) */
|
||||
ZSTD_p_enableLongDistanceMatching=1200, </b>/* Enable long distance matching.<b>
|
||||
* This parameter is designed to improve the compression
|
||||
* ratio for large inputs with long distance matches.
|
||||
* This increases the memory usage as well as window size.
|
||||
* Note: setting this parameter sets all the LDM parameters
|
||||
* as well as ZSTD_p_windowLog. It should be set after
|
||||
* ZSTD_p_compressionLevel and before ZSTD_p_windowLog and
|
||||
* other LDM parameters. Setting the compression level
|
||||
* after this parameter overrides the window log, though LDM
|
||||
* will remain enabled until explicitly disabled. */
|
||||
ZSTD_p_ldmHashLog, </b>/* Size of the table for long distance matching, as a power of 2.<b>
|
||||
* 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). */
|
||||
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
|
||||
* and ZSTD_LDM_MINMATCH_MAX (default: 64). */
|
||||
ZSTD_p_ldmBucketSizeLog, </b>/* Log size of each bucket in the LDM hash table for collision resolution.<b>
|
||||
* Larger values usually improve collision resolution but may decrease
|
||||
* compression speed.
|
||||
* The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX (default: 3). */
|
||||
ZSTD_p_ldmHashEveryLog, </b>/* Frequency of inserting/looking up entries in the LDM hash table.<b>
|
||||
* The default is MAX(0, (windowLog - ldmHashLog)) to
|
||||
* optimize hash table usage.
|
||||
* Larger values improve compression speed. Deviating far from the
|
||||
* default value will likely result in a decrease in compression ratio.
|
||||
* Must be clamped between 0 and ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN. */
|
||||
|
||||
} ZSTD_cParameter;
|
||||
</b></pre><BR>
|
||||
@@ -895,25 +861,18 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
|
||||
size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
|
||||
size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode);
|
||||
</b><p> Create an internal CDict from dict buffer.
|
||||
Decompression will have to use same buffer.
|
||||
@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_CCtx_loadDictionary_byReference() to reference dictionary
|
||||
content instead. The dictionary buffer must then outlive its
|
||||
users.
|
||||
Note 1 : `dict` content will be copied internally,
|
||||
except if ZSTD_p_refDictContent is set before loading.
|
||||
Note 2 : Loading a dictionary involves building tables, which are dependent on compression parameters.
|
||||
For this reason, compression parameters cannot be changed anymore after loading a dictionary.
|
||||
It's also a CPU-heavy operation, with non-negligible impact on latency.
|
||||
Note 3 : Dictionary will be used for all future compression jobs.
|
||||
To return to "no-dictionary" situation, load a NULL dictionary
|
||||
Note 5 : Use ZSTD_CCtx_loadDictionary_advanced() to select how dictionary
|
||||
content will be interpreted.
|
||||
|
||||
To return to "no-dictionary" situation, load a NULL dictionary
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
|
||||
@@ -930,7 +889,6 @@ size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize);
|
||||
size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode);
|
||||
</b><p> Reference a prefix (single-usage dictionary) for next compression job.
|
||||
Decompression need same prefix to properly regenerate data.
|
||||
Prefix is **only used once**. Tables are discarded at end of compression job.
|
||||
@@ -941,9 +899,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
||||
Note 1 : Prefix buffer is referenced. It must outlive compression job.
|
||||
Note 2 : Referencing a prefix involves building tables, which are dependent on compression parameters.
|
||||
It's a CPU-heavy operation, with non-negligible impact on latency.
|
||||
Note 3 : By default, the prefix is treated as raw content
|
||||
(ZSTD_dm_rawContent). Use ZSTD_CCtx_refPrefix_advanced() to alter
|
||||
dictMode.
|
||||
Note 3 : it's possible to alter ZSTD_p_dictMode using ZSTD_CCtx_setParameter()
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>typedef enum {
|
||||
@@ -993,57 +949,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter20"></a><h2>ZSTD_CCtx_params</h2><pre>
|
||||
- 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_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.
|
||||
|
||||
<BR></pre>
|
||||
|
||||
<pre><b>size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params);
|
||||
</b><p> Reset params to default, with the default compression level.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, int compressionLevel);
|
||||
</b><p> Initializes the compression parameters of cctxParams according to
|
||||
compression level. All other parameters are reset to their default values.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_initCCtxParams_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params);
|
||||
</b><p> Initializes the compression and frame parameters of cctxParams according to
|
||||
params. All other parameters are reset to their default values.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value);
|
||||
</b><p> Similar to ZSTD_CCtx_setParameter.
|
||||
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()).
|
||||
|
||||
</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.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter21"></a><h2>Block functions</h2><pre>
|
||||
<a name="Chapter20"></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).
|
||||
User will have to take in charge required information to regenerate data, such as compressed and content sizes.
|
||||
@@ -1071,7 +977,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
||||
<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);
|
||||
size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||
size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); </b>/**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression */<b>
|
||||
size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); </b>/**< insert block into `dctx` history. Useful for uncompressed blocks */<b>
|
||||
</pre></b><BR>
|
||||
</html>
|
||||
</body>
|
||||
|
||||
@@ -6,7 +6,6 @@ dictionary_decompression
|
||||
streaming_compression
|
||||
streaming_decompression
|
||||
multiple_streaming_compression
|
||||
streaming_memory_usage
|
||||
|
||||
#test artefact
|
||||
tmp*
|
||||
|
||||
+13
-21
@@ -2,14 +2,14 @@
|
||||
# Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# 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 Makefile presumes libzstd is installed, using `sudo make install`
|
||||
|
||||
LIB = ../lib/libzstd.a
|
||||
LDFLAGS += -lzstd
|
||||
|
||||
.PHONY: default all clean test
|
||||
|
||||
@@ -18,33 +18,27 @@ default: all
|
||||
all: simple_compression simple_decompression \
|
||||
dictionary_compression dictionary_decompression \
|
||||
streaming_compression streaming_decompression \
|
||||
multiple_streaming_compression streaming_memory_usage
|
||||
multiple_streaming_compression
|
||||
|
||||
$(LIB) :
|
||||
make -C ../lib libzstd.a
|
||||
|
||||
simple_compression : simple_compression.c $(LIB)
|
||||
simple_compression : simple_compression.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||
|
||||
simple_decompression : simple_decompression.c $(LIB)
|
||||
simple_decompression : simple_decompression.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||
|
||||
dictionary_compression : dictionary_compression.c $(LIB)
|
||||
dictionary_compression : dictionary_compression.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||
|
||||
dictionary_decompression : dictionary_decompression.c $(LIB)
|
||||
dictionary_decompression : dictionary_decompression.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||
|
||||
streaming_compression : streaming_compression.c $(LIB)
|
||||
streaming_compression : streaming_compression.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||
|
||||
multiple_streaming_compression : multiple_streaming_compression.c $(LIB)
|
||||
multiple_streaming_compression : multiple_streaming_compression.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||
|
||||
streaming_decompression : streaming_decompression.c $(LIB)
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||
|
||||
streaming_memory_usage : streaming_memory_usage.c $(LIB)
|
||||
streaming_decompression : streaming_decompression.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||
|
||||
clean:
|
||||
@@ -52,7 +46,7 @@ clean:
|
||||
simple_compression simple_decompression \
|
||||
dictionary_compression dictionary_decompression \
|
||||
streaming_compression streaming_decompression \
|
||||
multiple_streaming_compression streaming_memory_usage
|
||||
multiple_streaming_compression
|
||||
@echo Cleaning completed
|
||||
|
||||
test: all
|
||||
@@ -62,8 +56,6 @@ test: all
|
||||
./simple_compression tmp
|
||||
./simple_decompression tmp.zst
|
||||
./streaming_decompression tmp.zst > /dev/null
|
||||
@echo -- Streaming memory usage
|
||||
./streaming_memory_usage
|
||||
@echo -- Streaming compression tests
|
||||
./streaming_compression tmp
|
||||
./streaming_decompression tmp.zst > /dev/null
|
||||
|
||||
@@ -11,10 +11,6 @@ Zstandard library : usage examples
|
||||
Result remains in memory.
|
||||
Introduces usage of : `ZSTD_decompress()`
|
||||
|
||||
- [Streaming memory usage](streaming_memory_usage.c) :
|
||||
Provides amount of memory used by streaming context
|
||||
Introduces usage of : `ZSTD_sizeof_CStream()`
|
||||
|
||||
- [Streaming compression](streaming_compression.c) :
|
||||
Compress a single file.
|
||||
Introduces usage of : `ZSTD_compressStream()`
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#include <stdlib.h> // malloc, exit
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
|
||||
/*=== Tuning parameter ===*/
|
||||
#ifndef MAX_TESTED_LEVEL
|
||||
#define MAX_TESTED_LEVEL 12
|
||||
#endif
|
||||
|
||||
|
||||
/*=== Dependencies ===*/
|
||||
#include <stdio.h> /* printf */
|
||||
#define ZSTD_STATIC_LINKING_ONLY
|
||||
#include "zstd.h"
|
||||
|
||||
|
||||
/*=== functions ===*/
|
||||
|
||||
/*! readU32FromChar() :
|
||||
@return : unsigned integer value read from input in `char` format
|
||||
allows and interprets K, KB, KiB, M, MB and MiB suffix.
|
||||
Will also modify `*stringPtr`, advancing it to position where it stopped reading.
|
||||
Note : function result can overflow if digit string > MAX_UINT */
|
||||
static unsigned readU32FromChar(const char** stringPtr)
|
||||
{
|
||||
unsigned result = 0;
|
||||
while ((**stringPtr >='0') && (**stringPtr <='9'))
|
||||
result *= 10, result += **stringPtr - '0', (*stringPtr)++ ;
|
||||
if ((**stringPtr=='K') || (**stringPtr=='M')) {
|
||||
result <<= 10;
|
||||
if (**stringPtr=='M') result <<= 10;
|
||||
(*stringPtr)++ ;
|
||||
if (**stringPtr=='i') (*stringPtr)++;
|
||||
if (**stringPtr=='B') (*stringPtr)++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char const *argv[]) {
|
||||
|
||||
printf("\n Zstandard (v%u) memory usage for streaming contexts : \n\n", ZSTD_versionNumber());
|
||||
|
||||
unsigned wLog = 0;
|
||||
if (argc > 1) {
|
||||
const char* valStr = argv[1];
|
||||
wLog = readU32FromChar(&valStr);
|
||||
}
|
||||
|
||||
int compressionLevel;
|
||||
for (compressionLevel = 1; compressionLevel <= MAX_TESTED_LEVEL; compressionLevel++) {
|
||||
#define INPUT_SIZE 5
|
||||
#define COMPRESSED_SIZE 128
|
||||
char const dataToCompress[INPUT_SIZE] = "abcde";
|
||||
char compressedData[COMPRESSED_SIZE];
|
||||
char decompressedData[INPUT_SIZE];
|
||||
ZSTD_CStream* const cstream = ZSTD_createCStream();
|
||||
if (cstream==NULL) {
|
||||
printf("Level %i : ZSTD_CStream Memory allocation failure \n", compressionLevel);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* forces compressor to use maximum memory size for given compression level,
|
||||
* by not providing any information on input size */
|
||||
ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, 0);
|
||||
if (wLog) { /* special mode : specific wLog */
|
||||
printf("Using custom compression parameter : level 1 + wLog=%u \n", wLog);
|
||||
params = ZSTD_getParams(1, 1 << wLog, 0);
|
||||
size_t const error = ZSTD_initCStream_advanced(cstream, NULL, 0, params, 0);
|
||||
if (ZSTD_isError(error)) {
|
||||
printf("ZSTD_initCStream_advanced error : %s \n", ZSTD_getErrorName(error));
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
size_t const error = ZSTD_initCStream(cstream, compressionLevel);
|
||||
if (ZSTD_isError(error)) {
|
||||
printf("ZSTD_initCStream error : %s \n", ZSTD_getErrorName(error));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t compressedSize;
|
||||
{ ZSTD_inBuffer inBuff = { dataToCompress, sizeof(dataToCompress), 0 };
|
||||
ZSTD_outBuffer outBuff = { compressedData, sizeof(compressedData), 0 };
|
||||
size_t const cError = ZSTD_compressStream(cstream, &outBuff, &inBuff);
|
||||
if (ZSTD_isError(cError)) {
|
||||
printf("ZSTD_compressStream error : %s \n", ZSTD_getErrorName(cError));
|
||||
return 1;
|
||||
}
|
||||
size_t const fError = ZSTD_endStream(cstream, &outBuff);
|
||||
if (ZSTD_isError(fError)) {
|
||||
printf("ZSTD_endStream error : %s \n", ZSTD_getErrorName(fError));
|
||||
return 1;
|
||||
}
|
||||
compressedSize = outBuff.pos;
|
||||
}
|
||||
|
||||
ZSTD_DStream* dstream = ZSTD_createDStream();
|
||||
if (dstream==NULL) {
|
||||
printf("Level %i : ZSTD_DStream Memory allocation failure \n", compressionLevel);
|
||||
return 1;
|
||||
}
|
||||
{ size_t const error = ZSTD_initDStream(dstream);
|
||||
if (ZSTD_isError(error)) {
|
||||
printf("ZSTD_initDStream error : %s \n", ZSTD_getErrorName(error));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* forces decompressor to use maximum memory size, as decompressed size is not known */
|
||||
{ ZSTD_inBuffer inBuff = { compressedData, compressedSize, 0 };
|
||||
ZSTD_outBuffer outBuff = { decompressedData, sizeof(decompressedData), 0 };
|
||||
size_t const dResult = ZSTD_decompressStream(dstream, &outBuff, &inBuff);
|
||||
if (ZSTD_isError(dResult)) {
|
||||
printf("ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(dResult));
|
||||
return 1;
|
||||
}
|
||||
if (dResult != 0) {
|
||||
printf("ZSTD_decompressStream error : unfinished decompression \n");
|
||||
return 1;
|
||||
}
|
||||
if (outBuff.pos != sizeof(dataToCompress)) {
|
||||
printf("ZSTD_decompressStream error : incorrect decompression \n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t const cstreamSize = ZSTD_sizeof_CStream(cstream);
|
||||
size_t const cstreamEstimatedSize = wLog ?
|
||||
ZSTD_estimateCStreamSize_advanced_usingCParams(params.cParams) :
|
||||
ZSTD_estimateCStreamSize(compressionLevel);
|
||||
size_t const dstreamSize = ZSTD_sizeof_DStream(dstream);
|
||||
|
||||
printf("Level %2i : Compression Mem = %5u KB (estimated : %5u KB) ; Decompression Mem = %4u KB \n",
|
||||
compressionLevel,
|
||||
(unsigned)(cstreamSize>>10), (unsigned)(cstreamEstimatedSize>>10), (unsigned)(dstreamSize>>10));
|
||||
|
||||
ZSTD_freeDStream(dstream);
|
||||
ZSTD_freeCStream(cstream);
|
||||
if (wLog) break; /* single test */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,3 +1,2 @@
|
||||
# make install artefact
|
||||
libzstd.pc
|
||||
libzstd-nomt
|
||||
|
||||
+26
-40
@@ -1,11 +1,13 @@
|
||||
# ################################################################
|
||||
# Copyright (c) 2015-present, Yann Collet, Facebook, Inc.
|
||||
# ##########################################################################
|
||||
# Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# ################################################################
|
||||
# This Makefile is validated for Linux, macOS, *BSD, Hurd, Solaris, MSYS2 targets
|
||||
#
|
||||
# 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.
|
||||
# ##########################################################################
|
||||
|
||||
# Version numbers
|
||||
LIBVER_MAJOR_SCRIPT:=`sed -n '/define ZSTD_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ./zstd.h`
|
||||
@@ -29,7 +31,7 @@ CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS)
|
||||
FLAGS = $(CPPFLAGS) $(CFLAGS)
|
||||
|
||||
|
||||
ZSTD_FILES := $(sort $(wildcard common/*.c compress/*.c decompress/*.c dictBuilder/*.c deprecated/*.c))
|
||||
ZSTD_FILES := $(wildcard common/*.c compress/*.c decompress/*.c dictBuilder/*.c deprecated/*.c)
|
||||
|
||||
ZSTD_LEGACY_SUPPORT ?= 4
|
||||
|
||||
@@ -101,19 +103,10 @@ lib-release lib-release-mt: DEBUGFLAGS :=
|
||||
lib-release: lib
|
||||
lib-release-mt: lib-mt
|
||||
|
||||
# Special case : building library in single-thread mode _and_ without zstdmt_compress.c
|
||||
ZSTDMT_FILES = compress/zstdmt_compress.c
|
||||
ZSTD_NOMT_FILES = $(filter-out $(ZSTDMT_FILES),$(ZSTD_FILES))
|
||||
libzstd-nomt: LDFLAGS += -shared -fPIC -fvisibility=hidden
|
||||
libzstd-nomt: $(ZSTD_NOMT_FILES)
|
||||
@echo compiling single-thread dynamic library $(LIBVER)
|
||||
@echo files : $(ZSTD_NOMT_FILES)
|
||||
@$(CC) $(FLAGS) $^ $(LDFLAGS) $(SONAME_FLAGS) -o $@
|
||||
|
||||
clean:
|
||||
@$(RM) -r *.dSYM # Mac OS-X specific
|
||||
@$(RM) core *.o *.a *.gcda *.$(SHARED_EXT) *.$(SHARED_EXT).* libzstd.pc
|
||||
@$(RM) dll/libzstd.dll dll/libzstd.lib libzstd-nomt*
|
||||
@$(RM) dll/libzstd.dll dll/libzstd.lib
|
||||
@$(RM) common/*.o compress/*.o decompress/*.o dictBuilder/*.o legacy/*.o deprecated/*.o
|
||||
@echo Cleaning library completed
|
||||
|
||||
@@ -122,17 +115,16 @@ clean:
|
||||
#-----------------------------------------------------------------------------
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS))
|
||||
|
||||
DESTDIR ?=
|
||||
# directory variables : GNU conventions prefer lowercase
|
||||
# see https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html
|
||||
# support both lower and uppercase (BSD), use uppercase in script
|
||||
prefix ?= /usr/local
|
||||
PREFIX ?= $(prefix)
|
||||
exec_prefix ?= $(PREFIX)
|
||||
libdir ?= $(exec_prefix)/lib
|
||||
LIBDIR ?= $(libdir)
|
||||
includedir ?= $(PREFIX)/include
|
||||
INCLUDEDIR ?= $(includedir)
|
||||
ifneq (,$(filter $(shell uname),SunOS))
|
||||
INSTALL ?= ginstall
|
||||
else
|
||||
INSTALL ?= install
|
||||
endif
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
DESTDIR ?=
|
||||
LIBDIR ?= $(PREFIX)/lib
|
||||
INCLUDEDIR ?= $(PREFIX)/include
|
||||
|
||||
ifneq (,$(filter $(shell uname),OpenBSD FreeBSD NetBSD DragonFly))
|
||||
PKGCONFIGDIR ?= $(PREFIX)/libdata/pkgconfig
|
||||
@@ -140,14 +132,8 @@ else
|
||||
PKGCONFIGDIR ?= $(LIBDIR)/pkgconfig
|
||||
endif
|
||||
|
||||
ifneq (,$(filter $(shell uname),SunOS))
|
||||
INSTALL ?= ginstall
|
||||
else
|
||||
INSTALL ?= install
|
||||
endif
|
||||
|
||||
INSTALL_PROGRAM ?= $(INSTALL)
|
||||
INSTALL_DATA ?= $(INSTALL) -m 644
|
||||
INSTALL_LIB ?= $(INSTALL) -m 755
|
||||
INSTALL_DATA ?= $(INSTALL) -m 644
|
||||
|
||||
|
||||
libzstd.pc:
|
||||
@@ -164,9 +150,9 @@ install: libzstd.a libzstd libzstd.pc
|
||||
@$(INSTALL_DATA) libzstd.pc $(DESTDIR)$(PKGCONFIGDIR)/
|
||||
@echo Installing libraries
|
||||
@$(INSTALL_DATA) libzstd.a $(DESTDIR)$(LIBDIR)
|
||||
@$(INSTALL_PROGRAM) $(LIBZSTD) $(DESTDIR)$(LIBDIR)
|
||||
@ln -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR)
|
||||
@ln -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT)
|
||||
@$(INSTALL_LIB) libzstd.$(SHARED_EXT_VER) $(DESTDIR)$(LIBDIR)
|
||||
@ln -sf libzstd.$(SHARED_EXT_VER) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR)
|
||||
@ln -sf libzstd.$(SHARED_EXT_VER) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT)
|
||||
@echo Installing includes
|
||||
@$(INSTALL_DATA) zstd.h $(DESTDIR)$(INCLUDEDIR)
|
||||
@$(INSTALL_DATA) common/zstd_errors.h $(DESTDIR)$(INCLUDEDIR)
|
||||
@@ -178,7 +164,7 @@ uninstall:
|
||||
@$(RM) $(DESTDIR)$(LIBDIR)/libzstd.a
|
||||
@$(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT)
|
||||
@$(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR)
|
||||
@$(RM) $(DESTDIR)$(LIBDIR)/$(LIBZSTD)
|
||||
@$(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_VER)
|
||||
@$(RM) $(DESTDIR)$(PKGCONFIGDIR)/libzstd.pc
|
||||
@$(RM) $(DESTDIR)$(INCLUDEDIR)/zstd.h
|
||||
@$(RM) $(DESTDIR)$(INCLUDEDIR)/zstd_errors.h
|
||||
|
||||
+43
-66
@@ -1,78 +1,57 @@
|
||||
Zstandard library files
|
||||
================================
|
||||
|
||||
The __lib__ directory is split into several sub-directories,
|
||||
in order to make it easier to select or exclude specific features.
|
||||
|
||||
|
||||
#### Building
|
||||
|
||||
`Makefile` script is provided, supporting the standard set of commands,
|
||||
directories, and variables (see https://www.gnu.org/prep/standards/html_node/Command-Variables.html).
|
||||
- `make` : generates both static and dynamic libraries
|
||||
- `make install` : install libraries in default system directories
|
||||
The __lib__ directory contains several directories.
|
||||
Depending on target use case, it's enough to include only files from relevant directories.
|
||||
|
||||
|
||||
#### API
|
||||
|
||||
Zstandard's stable API is exposed within [lib/zstd.h](zstd.h).
|
||||
Zstandard's stable API is exposed within [zstd.h](zstd.h),
|
||||
at the root of `lib` directory.
|
||||
|
||||
|
||||
#### Advanced API
|
||||
|
||||
Optional advanced features are exposed via :
|
||||
|
||||
- `lib/common/zstd_errors.h` : translates `size_t` function results
|
||||
into an `ZSTD_ErrorCode`, for accurate error handling.
|
||||
- `ZSTD_STATIC_LINKING_ONLY` : if this macro is defined _before_ including `zstd.h`,
|
||||
it unlocks access to advanced experimental API,
|
||||
exposed in second part of `zstd.h`.
|
||||
Some additional API may be useful if you're looking into advanced features :
|
||||
- common/error_public.h : transforms `size_t` function results into an `enum`,
|
||||
for precise error handling.
|
||||
- ZSTD_STATIC_LINKING_ONLY : if you define this macro _before_ including `zstd.h`,
|
||||
it will give access to advanced and experimental API.
|
||||
These APIs shall ___never be used with dynamic library___ !
|
||||
They are not "stable", their definition may change in the future.
|
||||
Only static linking is allowed.
|
||||
|
||||
#### ZSTDMT API
|
||||
|
||||
To enable multithreaded compression within the library, invoke `make lib-mt` target.
|
||||
Prototypes are defined in header file `compress/zstdmt_compress.h`.
|
||||
When linking a program that uses ZSTDMT API against libzstd.a on a POSIX system,
|
||||
`-pthread` flag must be provided to the compiler and linker.
|
||||
Note : ZSTDMT prototypes can still be used with a library built without multithread support,
|
||||
but in this case, they will be single threaded only.
|
||||
|
||||
#### Modular build
|
||||
|
||||
- Directory `lib/common` is always required, for all variants.
|
||||
- Compression source code lies in `lib/compress`
|
||||
- Decompression source code lies in `lib/decompress`
|
||||
- It's possible to include only `compress` or only `decompress`, they don't depend on each other.
|
||||
- `lib/dictBuilder` : makes it possible to generate dictionaries from a set of samples.
|
||||
The API is exposed in `lib/dictBuilder/zdict.h`.
|
||||
This module depends on both `lib/common` and `lib/compress` .
|
||||
- `lib/legacy` : source code to decompress older zstd formats, starting from `v0.1`.
|
||||
This module depends on `lib/common` and `lib/decompress`.
|
||||
To enable this feature, it's necessary to define `ZSTD_LEGACY_SUPPORT = 1` during compilation.
|
||||
Typically, with `gcc`, add argument `-DZSTD_LEGACY_SUPPORT=1`.
|
||||
Using higher number limits the number of version supported.
|
||||
For example, `ZSTD_LEGACY_SUPPORT=2` means : "support legacy formats starting from v0.2+".
|
||||
The API is exposed in `lib/legacy/zstd_legacy.h`.
|
||||
Each version also provides a (dedicated) set of advanced API.
|
||||
For example, advanced API for version `v0.4` is exposed in `lib/legacy/zstd_v04.h` .
|
||||
Directory `common/` is required in all circumstances.
|
||||
You can select to support compression only, by just adding files from the `compress/` directory,
|
||||
In a similar way, you can build a decompressor-only library with the `decompress/` directory.
|
||||
|
||||
Other optional functionalities provided are :
|
||||
|
||||
- `dictBuilder/` : source files to create dictionaries.
|
||||
The API can be consulted in `dictBuilder/zdict.h`.
|
||||
This module also depends on `common/` and `compress/` .
|
||||
|
||||
- `legacy/` : source code to decompress previous versions of zstd, starting from `v0.1`.
|
||||
This module also depends on `common/` and `decompress/` .
|
||||
Library compilation must include directive `ZSTD_LEGACY_SUPPORT = 1` .
|
||||
The main API can be consulted in `legacy/zstd_legacy.h`.
|
||||
Advanced API from each version can be found in their relevant header file.
|
||||
For example, advanced API for version `v0.4` is in `legacy/zstd_v04.h` .
|
||||
|
||||
|
||||
#### Multithreading support
|
||||
|
||||
Multithreading is disabled by default when building with `make`.
|
||||
Enabling multithreading requires 2 conditions :
|
||||
- set macro `ZSTD_MULTITHREAD`
|
||||
- on POSIX systems : compile with pthread (`-pthread` compilation flag for `gcc` for example)
|
||||
|
||||
Both conditions are automatically triggered by invoking `make lib-mt` target.
|
||||
Note that, when linking a POSIX program with a multithreaded version of `libzstd`,
|
||||
it's necessary to trigger `-pthread` flag during link stage.
|
||||
|
||||
Multithreading capabilities are exposed via :
|
||||
- private API `lib/compress/zstdmt_compress.h`.
|
||||
Symbols defined in this header are currently exposed in `libzstd`, hence usable.
|
||||
Note however that this API is planned to be locked and remain strictly internal in the future.
|
||||
- advanced API `ZSTD_compress_generic()`, defined in `lib/zstd.h`, experimental section.
|
||||
This API is still considered experimental, but is designed to be labelled "stable" at some point in the future.
|
||||
It's the recommended entry point for multi-threading operations.
|
||||
|
||||
|
||||
#### Windows : using MinGW+MSYS to create DLL
|
||||
#### Using MinGW+MSYS to create DLL
|
||||
|
||||
DLL can be created using MinGW+MSYS with the `make libzstd` command.
|
||||
This command creates `dll\libzstd.dll` and the import library `dll\libzstd.lib`.
|
||||
@@ -88,21 +67,19 @@ file it should be linked with `dll\libzstd.dll`. For example:
|
||||
The compiled executable will require ZSTD DLL which is available at `dll\libzstd.dll`.
|
||||
|
||||
|
||||
#### Deprecated API
|
||||
#### Obsolete streaming API
|
||||
|
||||
Obsolete API on their way out are stored in directory `lib/deprecated`.
|
||||
At this stage, it contains older streaming prototypes, in `lib/deprecated/zbuff.h`.
|
||||
Presence in this directory is temporary.
|
||||
These prototypes will be removed in some future version.
|
||||
Consider migrating code towards supported streaming API exposed in `zstd.h`.
|
||||
Streaming is now provided within `zstd.h`.
|
||||
Older streaming API is still available within `deprecated/zbuff.h`.
|
||||
It will be removed in a future version.
|
||||
Consider migrating code towards newer streaming API in `zstd.h`.
|
||||
|
||||
|
||||
#### Miscellaneous
|
||||
|
||||
The other files are not source code. There are :
|
||||
|
||||
- `LICENSE` : contains the BSD license text
|
||||
- `Makefile` : `make` script to build and install zstd library (static and dynamic)
|
||||
- `BUCK` : support for `buck` build system (https://buckbuild.com/)
|
||||
- `libzstd.pc.in` : for `pkg-config` (used in `make install`)
|
||||
- `README.md` : this file
|
||||
- LICENSE : contains the BSD license text
|
||||
- Makefile : script to compile or install zstd library (static and dynamic)
|
||||
- libzstd.pc.in : for pkg-config (`make install`)
|
||||
- README.md : this file
|
||||
|
||||
+15
-18
@@ -169,28 +169,25 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
|
||||
****************************************************************/
|
||||
MEM_STATIC unsigned BIT_highbit32 (register U32 val)
|
||||
{
|
||||
assert(val != 0);
|
||||
{
|
||||
# if defined(_MSC_VER) /* Visual */
|
||||
unsigned long r=0;
|
||||
_BitScanReverse ( &r, val );
|
||||
return (unsigned) r;
|
||||
unsigned long r=0;
|
||||
_BitScanReverse ( &r, val );
|
||||
return (unsigned) r;
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */
|
||||
return 31 - __builtin_clz (val);
|
||||
return 31 - __builtin_clz (val);
|
||||
# else /* Software version */
|
||||
static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29,
|
||||
11, 14, 16, 18, 22, 25, 3, 30,
|
||||
8, 12, 20, 28, 15, 17, 24, 7,
|
||||
19, 27, 23, 6, 26, 5, 4, 31 };
|
||||
U32 v = val;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
|
||||
static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29,
|
||||
11, 14, 16, 18, 22, 25, 3, 30,
|
||||
8, 12, 20, 28, 15, 17, 24, 7,
|
||||
19, 27, 23, 6, 26, 5, 4, 31 };
|
||||
U32 v = val;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
/*===== Local Constants =====*/
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_COMPILER_H
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
/* The purpose of this file is to have a single list of error strings embedded in binary */
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
/* Note : this module is expected to remain private, do not expose it */
|
||||
@@ -49,9 +48,10 @@ typedef ZSTD_ErrorCode ERR_enum;
|
||||
/*-****************************************
|
||||
* Error codes handling
|
||||
******************************************/
|
||||
#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */
|
||||
#define ERROR(name) ZSTD_ERROR(name)
|
||||
#define ZSTD_ERROR(name) ((size_t)-PREFIX(name))
|
||||
#ifdef ERROR
|
||||
# undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */
|
||||
#endif
|
||||
#define ERROR(name) ((size_t)-PREFIX(name))
|
||||
|
||||
ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); }
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef MEM_H_MODULE
|
||||
|
||||
+14
-29
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -26,12 +25,11 @@
|
||||
|
||||
/* A job is a function and an opaque argument */
|
||||
typedef struct POOL_job_s {
|
||||
POOL_function function;
|
||||
void *opaque;
|
||||
POOL_function function;
|
||||
void *opaque;
|
||||
} POOL_job;
|
||||
|
||||
struct POOL_ctx_s {
|
||||
ZSTD_customMem customMem;
|
||||
/* Keep track of the threads */
|
||||
pthread_t *threads;
|
||||
size_t numThreads;
|
||||
@@ -100,15 +98,11 @@ static void* POOL_thread(void* opaque) {
|
||||
}
|
||||
|
||||
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;
|
||||
/* 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 *)calloc(1, sizeof(POOL_ctx));
|
||||
if (!ctx) { return NULL; }
|
||||
/* Initialize the job queue.
|
||||
* It needs one extra space since one space is wasted to differentiate empty
|
||||
@@ -125,9 +119,8 @@ POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM
|
||||
(void)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 = (pthread_t*)malloc(numThreads * sizeof(pthread_t));
|
||||
ctx->numThreads = 0;
|
||||
ctx->customMem = customMem;
|
||||
/* Check for errors */
|
||||
if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; }
|
||||
/* Initialize the threads */
|
||||
@@ -167,9 +160,9 @@ void POOL_free(POOL_ctx *ctx) {
|
||||
pthread_mutex_destroy(&ctx->queueMutex);
|
||||
pthread_cond_destroy(&ctx->queuePushCond);
|
||||
pthread_cond_destroy(&ctx->queuePopCond);
|
||||
ZSTD_free(ctx->queue, ctx->customMem);
|
||||
ZSTD_free(ctx->threads, ctx->customMem);
|
||||
ZSTD_free(ctx, ctx->customMem);
|
||||
if (ctx->queue) free(ctx->queue);
|
||||
if (ctx->threads) free(ctx->threads);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
size_t POOL_sizeof(POOL_ctx *ctx) {
|
||||
@@ -221,34 +214,26 @@ void POOL_add(void* ctxVoid, POOL_function function, void *opaque) {
|
||||
|
||||
/* We don't need any data, but if it is empty malloc() might return NULL. */
|
||||
struct POOL_ctx_s {
|
||||
int dummy;
|
||||
int data;
|
||||
};
|
||||
static POOL_ctx g_ctx;
|
||||
|
||||
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) {
|
||||
(void)numThreads;
|
||||
(void)queueSize;
|
||||
(void)customMem;
|
||||
return &g_ctx;
|
||||
(void)numThreads;
|
||||
(void)queueSize;
|
||||
return (POOL_ctx*)malloc(sizeof(POOL_ctx));
|
||||
}
|
||||
|
||||
void POOL_free(POOL_ctx* ctx) {
|
||||
assert(!ctx || ctx == &g_ctx);
|
||||
(void)ctx;
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
void POOL_add(void* ctx, POOL_function function, void* opaque) {
|
||||
(void)ctx;
|
||||
function(opaque);
|
||||
(void)ctx;
|
||||
function(opaque);
|
||||
}
|
||||
|
||||
size_t POOL_sizeof(POOL_ctx* ctx) {
|
||||
if (ctx==NULL) return 0; /* supports sizeof NULL */
|
||||
assert(ctx == &g_ctx);
|
||||
return sizeof(*ctx);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef POOL_H
|
||||
@@ -17,7 +16,6 @@ extern "C" {
|
||||
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
#include "zstd_internal.h" /* ZSTD_customMem */
|
||||
|
||||
typedef struct POOL_ctx_s POOL_ctx;
|
||||
|
||||
@@ -29,8 +27,6 @@ typedef struct POOL_ctx_s POOL_ctx;
|
||||
*/
|
||||
POOL_ctx *POOL_create(size_t numThreads, size_t queueSize);
|
||||
|
||||
POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem);
|
||||
|
||||
/*! POOL_free() :
|
||||
Free a thread pool returned by POOL_create().
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
* Copyright (c) 2016 Tino Reichardt
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - zstdmt source repository: https://github.com/mcmilk/zstdmt
|
||||
@@ -14,8 +14,12 @@
|
||||
* This file will hold wrapper for systems, which do not support pthreads
|
||||
*/
|
||||
|
||||
/* create fake symbol to avoid empty trnaslation unit warning */
|
||||
int g_ZSTD_threading_useles_symbol;
|
||||
/* When ZSTD_MULTITHREAD is not defined, this file would become an empty translation unit.
|
||||
* Include some ISO C header code to prevent this and portably avoid related warnings.
|
||||
* (Visual C++: C4206 / GCC: -Wpedantic / Clang: -Wempty-translation-unit)
|
||||
*/
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#if defined(ZSTD_MULTITHREAD) && defined(_WIN32)
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
* Copyright (c) 2016 Tino Reichardt
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - zstdmt source repository: https://github.com/mcmilk/zstdmt
|
||||
@@ -37,11 +37,7 @@ extern "C" {
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */
|
||||
#include <windows.h>
|
||||
#undef ERROR
|
||||
#define ERROR(name) ZSTD_ERROR(name)
|
||||
|
||||
|
||||
/* mutex */
|
||||
#define pthread_mutex_t CRITICAL_SECTION
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -16,7 +15,8 @@
|
||||
#include <stdlib.h> /* malloc, calloc, free */
|
||||
#include <string.h> /* memset */
|
||||
#include "error_private.h"
|
||||
#include "zstd_internal.h"
|
||||
#define ZSTD_STATIC_LINKING_ONLY
|
||||
#include "zstd.h"
|
||||
|
||||
|
||||
/*-****************************************
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_ERRORS_H_398273423
|
||||
|
||||
+17
-85
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_CCOMMON_H_MODULE
|
||||
@@ -30,11 +29,6 @@
|
||||
#include "xxhash.h" /* XXH_reset, update, digest */
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Debug
|
||||
***************************************/
|
||||
@@ -249,26 +243,6 @@ typedef struct {
|
||||
const BYTE* cachedLiterals;
|
||||
} optState_t;
|
||||
|
||||
typedef struct {
|
||||
U32 offset;
|
||||
U32 checksum;
|
||||
} ldmEntry_t;
|
||||
|
||||
typedef struct {
|
||||
ldmEntry_t* hashTable;
|
||||
BYTE* bucketOffsets; /* Next position in bucket to insert entry */
|
||||
U64 hashPower; /* Used to compute the rolling hash.
|
||||
* Depends on ldmParams.minMatchLength */
|
||||
} ldmState_t;
|
||||
|
||||
typedef struct {
|
||||
U32 enableLdm; /* 1 if enable long distance matching */
|
||||
U32 hashLog; /* Log size of hashTable */
|
||||
U32 bucketSizeLog; /* Log bucket size for collision resolution, at most 8 */
|
||||
U32 minMatchLength; /* Minimum match length */
|
||||
U32 hashEveryLog; /* Log number of entries to skip */
|
||||
} ldmParams_t;
|
||||
|
||||
typedef struct {
|
||||
U32 hufCTable[HUF_CTABLE_SIZE_U32(255)];
|
||||
FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
|
||||
@@ -281,27 +255,6 @@ typedef struct {
|
||||
FSE_repeat litlength_repeatMode;
|
||||
} ZSTD_entropyCTables_t;
|
||||
|
||||
struct ZSTD_CCtx_params_s {
|
||||
ZSTD_compressionParameters cParams;
|
||||
ZSTD_frameParameters fParams;
|
||||
|
||||
int compressionLevel;
|
||||
U32 forceWindow; /* force back-references to respect limit of
|
||||
* 1<<wLog, even for dictionary */
|
||||
|
||||
/* Multithreading: used to pass parameters to mtctx */
|
||||
U32 nbThreads;
|
||||
unsigned jobSize;
|
||||
unsigned overlapSizeLog;
|
||||
|
||||
/* Long distance matching parameters */
|
||||
ldmParams_t ldmParams;
|
||||
|
||||
/* For use with createCCtxParams() and freeCCtxParams() only */
|
||||
ZSTD_customMem customMem;
|
||||
|
||||
}; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */
|
||||
|
||||
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx);
|
||||
void ZSTD_seqToCodes(const seqStore_t* seqStorePtr);
|
||||
|
||||
@@ -315,27 +268,24 @@ void ZSTD_free(void* ptr, ZSTD_customMem customMem);
|
||||
|
||||
MEM_STATIC U32 ZSTD_highbit32(U32 val)
|
||||
{
|
||||
assert(val != 0);
|
||||
{
|
||||
# if defined(_MSC_VER) /* Visual */
|
||||
unsigned long r=0;
|
||||
_BitScanReverse(&r, val);
|
||||
return (unsigned)r;
|
||||
unsigned long r=0;
|
||||
_BitScanReverse(&r, val);
|
||||
return (unsigned)r;
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
|
||||
return 31 - __builtin_clz(val);
|
||||
return 31 - __builtin_clz(val);
|
||||
# else /* Software version */
|
||||
static const int DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
|
||||
U32 v = val;
|
||||
int r;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27];
|
||||
return r;
|
||||
static const int DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
|
||||
U32 v = val;
|
||||
int r;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27];
|
||||
return r;
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -356,7 +306,7 @@ void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx);
|
||||
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);
|
||||
ZSTD_parameters params, unsigned long long pledgedSrcSize);
|
||||
|
||||
/*! ZSTD_compressStream_generic() :
|
||||
* Private use only. To be called from zstdmt_compress.c in single-thread mode. */
|
||||
@@ -365,25 +315,10 @@ size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
|
||||
ZSTD_inBuffer* input,
|
||||
ZSTD_EndDirective const flushMode);
|
||||
|
||||
/*! ZSTD_getCParamsFromCDict() :
|
||||
/*! ZSTD_getParamsFromCDict() :
|
||||
* as the name implies */
|
||||
ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict);
|
||||
ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict);
|
||||
|
||||
/* ZSTD_compressBegin_advanced_internal() :
|
||||
* Private use only. To be called from zstdmt_compress.c. */
|
||||
size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictMode_e dictMode,
|
||||
ZSTD_CCtx_params params,
|
||||
unsigned long long pledgedSrcSize);
|
||||
|
||||
/* ZSTD_compress_advanced_internal() :
|
||||
* Private use only. To be called from zstdmt_compress.c. */
|
||||
size_t ZSTD_compress_advanced_internal(ZSTD_CCtx* cctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
const void* dict,size_t dictSize,
|
||||
ZSTD_CCtx_params params);
|
||||
|
||||
typedef struct {
|
||||
blockType_e blockType;
|
||||
@@ -396,8 +331,5 @@ typedef struct {
|
||||
size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
|
||||
blockProperties_t* bpPtr);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZSTD_CCOMMON_H_MODULE */
|
||||
|
||||
+1869
-629
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -26,12 +25,16 @@
|
||||
#include "fse.h"
|
||||
#define HUF_STATIC_LINKING_ONLY
|
||||
#include "huf.h"
|
||||
#include "zstd_compress.h"
|
||||
#include "zstd_fast.h"
|
||||
#include "zstd_double_fast.h"
|
||||
#include "zstd_lazy.h"
|
||||
#include "zstd_opt.h"
|
||||
#include "zstd_ldm.h"
|
||||
#include "zstd_internal.h" /* includes zstd.h */
|
||||
#include "zstdmt_compress.h"
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Constants
|
||||
***************************************/
|
||||
static const U32 g_searchStrength = 8; /* control skip over incompressible data */
|
||||
#define HASH_READ_SIZE 8
|
||||
typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
|
||||
|
||||
|
||||
/*-*************************************
|
||||
@@ -58,6 +61,8 @@ static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
|
||||
/*-*************************************
|
||||
* Context memory management
|
||||
***************************************/
|
||||
typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage;
|
||||
|
||||
struct ZSTD_CDict_s {
|
||||
void* dictBuffer;
|
||||
const void* dictContent;
|
||||
@@ -65,6 +70,65 @@ struct ZSTD_CDict_s {
|
||||
ZSTD_CCtx* refContext;
|
||||
}; /* typedef'd to ZSTD_CDict within "zstd.h" */
|
||||
|
||||
struct ZSTD_CCtx_s {
|
||||
const BYTE* nextSrc; /* next block here to continue on current prefix */
|
||||
const BYTE* base; /* All regular indexes relative to this position */
|
||||
const BYTE* dictBase; /* extDict indexes relative to this position */
|
||||
U32 dictLimit; /* below that point, need extDict */
|
||||
U32 lowLimit; /* below that point, no more data */
|
||||
U32 nextToUpdate; /* index from which to continue dictionary update */
|
||||
U32 nextToUpdate3; /* index from which to continue dictionary update */
|
||||
U32 hashLog3; /* dispatch table : larger == faster, more memory */
|
||||
U32 loadedDictEnd; /* index of end of dictionary */
|
||||
U32 forceWindow; /* force back-references to respect limit of 1<<wLog, even for dictionary */
|
||||
ZSTD_compressionStage_e stage;
|
||||
U32 dictID;
|
||||
int compressionLevel;
|
||||
ZSTD_parameters requestedParams;
|
||||
ZSTD_parameters appliedParams;
|
||||
void* workSpace;
|
||||
size_t workSpaceSize;
|
||||
size_t blockSize;
|
||||
U64 pledgedSrcSizePlusOne; /* this way, 0 (default) == unknown */
|
||||
U64 consumedSrcSize;
|
||||
XXH64_state_t xxhState;
|
||||
ZSTD_customMem customMem;
|
||||
size_t staticSize;
|
||||
|
||||
seqStore_t seqStore; /* sequences storage ptrs */
|
||||
optState_t optState;
|
||||
U32* hashTable;
|
||||
U32* hashTable3;
|
||||
U32* chainTable;
|
||||
ZSTD_entropyCTables_t* entropy;
|
||||
|
||||
/* streaming */
|
||||
char* inBuff;
|
||||
size_t inBuffSize;
|
||||
size_t inToCompress;
|
||||
size_t inBuffPos;
|
||||
size_t inBuffTarget;
|
||||
char* outBuff;
|
||||
size_t outBuffSize;
|
||||
size_t outBuffContentSize;
|
||||
size_t outBuffFlushedSize;
|
||||
ZSTD_cStreamStage streamStage;
|
||||
U32 frameEnded;
|
||||
|
||||
/* Dictionary */
|
||||
ZSTD_dictMode_e dictMode; /* select restricting dictionary to "rawContent" or "fullDict" only */
|
||||
U32 dictContentByRef;
|
||||
ZSTD_CDict* cdictLocal;
|
||||
const ZSTD_CDict* cdict;
|
||||
const void* prefix;
|
||||
size_t prefixSize;
|
||||
|
||||
/* Multi-threading */
|
||||
U32 nbThreads;
|
||||
ZSTDMT_CCtx* mtctx;
|
||||
};
|
||||
|
||||
|
||||
ZSTD_CCtx* ZSTD_createCCtx(void)
|
||||
{
|
||||
return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
|
||||
@@ -79,7 +143,7 @@ ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
|
||||
cctx = (ZSTD_CCtx*) ZSTD_calloc(sizeof(ZSTD_CCtx), customMem);
|
||||
if (!cctx) return NULL;
|
||||
cctx->customMem = customMem;
|
||||
cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_DEFAULT;
|
||||
cctx->compressionLevel = ZSTD_CLEVEL_DEFAULT;
|
||||
ZSTD_STATIC_ASSERT(zcss_init==0);
|
||||
ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
|
||||
return cctx;
|
||||
@@ -87,7 +151,7 @@ ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
|
||||
|
||||
ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
|
||||
{
|
||||
ZSTD_CCtx* const cctx = (ZSTD_CCtx*) workspace;
|
||||
ZSTD_CCtx* cctx = (ZSTD_CCtx*) workspace;
|
||||
if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
|
||||
if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
|
||||
memset(workspace, 0, workspaceSize); /* may be a bit generous, could memset be smaller ? */
|
||||
@@ -97,7 +161,7 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
|
||||
|
||||
/* entropy space (never moves) */
|
||||
if (cctx->workSpaceSize < sizeof(ZSTD_entropyCTables_t)) return NULL;
|
||||
assert(((size_t)cctx->workSpace & (sizeof(void*)-1)) == 0); /* ensure correct alignment */
|
||||
assert(((size_t)cctx->workSpace & 7) == 0); /* ensure correct alignment */
|
||||
cctx->entropy = (ZSTD_entropyCTables_t*)cctx->workSpace;
|
||||
|
||||
return cctx;
|
||||
@@ -111,36 +175,23 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
|
||||
cctx->workSpace = NULL;
|
||||
ZSTD_freeCDict(cctx->cdictLocal);
|
||||
cctx->cdictLocal = NULL;
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
ZSTDMT_freeCCtx(cctx->mtctx);
|
||||
cctx->mtctx = NULL;
|
||||
#endif
|
||||
ZSTD_free(cctx, cctx->customMem);
|
||||
return 0; /* reserved as a potential error code in the future */
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx)
|
||||
{
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
return ZSTDMT_sizeof_CCtx(cctx->mtctx);
|
||||
#else
|
||||
(void) cctx;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
|
||||
{
|
||||
if (cctx==NULL) return 0; /* support sizeof on NULL */
|
||||
DEBUGLOG(3, "sizeof(*cctx) : %u", (U32)sizeof(*cctx));
|
||||
DEBUGLOG(3, "workSpaceSize (including streaming buffers): %u", (U32)cctx->workSpaceSize);
|
||||
DEBUGLOG(3, "inner cdict : %u", (U32)ZSTD_sizeof_CDict(cctx->cdictLocal));
|
||||
DEBUGLOG(3, "inner MTCTX : %u", (U32)ZSTD_sizeof_mtctx(cctx));
|
||||
DEBUGLOG(5, "sizeof(*cctx) : %u", (U32)sizeof(*cctx));
|
||||
DEBUGLOG(5, "workSpaceSize : %u", (U32)cctx->workSpaceSize);
|
||||
DEBUGLOG(5, "streaming buffers : %u", (U32)(cctx->outBuffSize + cctx->inBuffSize));
|
||||
DEBUGLOG(5, "inner MTCTX : %u", (U32)ZSTDMT_sizeof_CCtx(cctx->mtctx));
|
||||
return sizeof(*cctx) + cctx->workSpaceSize
|
||||
+ ZSTD_sizeof_CDict(cctx->cdictLocal)
|
||||
+ ZSTD_sizeof_mtctx(cctx);
|
||||
+ cctx->outBuffSize + cctx->inBuffSize
|
||||
+ ZSTDMT_sizeof_CCtx(cctx->mtctx);
|
||||
}
|
||||
|
||||
size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
|
||||
@@ -151,98 +202,29 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
|
||||
/* private API call, for dictBuilder only */
|
||||
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
|
||||
|
||||
static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { return cctx->appliedParams; }
|
||||
|
||||
/* older variant; will be deprecated */
|
||||
size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0;
|
||||
ZSTD_STATIC_ASSERT(ZSTD_dm_auto==0);
|
||||
ZSTD_STATIC_ASSERT(ZSTD_dm_rawContent==1);
|
||||
case ZSTD_p_forceRawDict : cctx->dictMode = (ZSTD_dictMode_e)(value>0); return 0;
|
||||
default: return ERROR(parameter_unsupported);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define ZSTD_CLEVEL_CUSTOM 999
|
||||
|
||||
static ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
|
||||
ZSTD_CCtx_params params, U64 srcSizeHint, size_t dictSize)
|
||||
{
|
||||
return (params.compressionLevel == ZSTD_CLEVEL_CUSTOM ?
|
||||
params.cParams :
|
||||
ZSTD_getCParams(params.compressionLevel, srcSizeHint, dictSize));
|
||||
}
|
||||
|
||||
static void ZSTD_cLevelToCCtxParams_srcSize(ZSTD_CCtx_params* params, U64 srcSize)
|
||||
{
|
||||
params->cParams = ZSTD_getCParamsFromCCtxParams(*params, srcSize, 0);
|
||||
params->compressionLevel = ZSTD_CLEVEL_CUSTOM;
|
||||
}
|
||||
|
||||
static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx)
|
||||
{
|
||||
ZSTD_cLevelToCCtxParams_srcSize(
|
||||
&cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1);
|
||||
}
|
||||
|
||||
static void ZSTD_cLevelToCCtxParams(ZSTD_CCtx_params* params)
|
||||
{
|
||||
ZSTD_cLevelToCCtxParams_srcSize(params, 0);
|
||||
}
|
||||
|
||||
static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
|
||||
ZSTD_compressionParameters cParams)
|
||||
{
|
||||
ZSTD_CCtx_params cctxParams;
|
||||
memset(&cctxParams, 0, sizeof(cctxParams));
|
||||
cctxParams.cParams = cParams;
|
||||
cctxParams.compressionLevel = ZSTD_CLEVEL_CUSTOM;
|
||||
return cctxParams;
|
||||
}
|
||||
|
||||
static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(
|
||||
ZSTD_customMem customMem)
|
||||
{
|
||||
ZSTD_CCtx_params* params;
|
||||
if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
|
||||
params = (ZSTD_CCtx_params*)ZSTD_calloc(
|
||||
sizeof(ZSTD_CCtx_params), customMem);
|
||||
if (!params) { return NULL; }
|
||||
params->customMem = customMem;
|
||||
params->compressionLevel = ZSTD_CLEVEL_DEFAULT;
|
||||
return params;
|
||||
}
|
||||
|
||||
ZSTD_CCtx_params* ZSTD_createCCtxParams(void)
|
||||
{
|
||||
return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem);
|
||||
}
|
||||
|
||||
size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params)
|
||||
{
|
||||
if (params == NULL) { return 0; }
|
||||
ZSTD_free(params, params->customMem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params)
|
||||
{
|
||||
return ZSTD_initCCtxParams(params, ZSTD_CLEVEL_DEFAULT);
|
||||
}
|
||||
|
||||
size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
|
||||
if (!cctxParams) { return ERROR(GENERIC); }
|
||||
memset(cctxParams, 0, sizeof(*cctxParams));
|
||||
cctxParams->compressionLevel = compressionLevel;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ZSTD_initCCtxParams_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
|
||||
{
|
||||
if (!cctxParams) { return ERROR(GENERIC); }
|
||||
CHECK_F( ZSTD_checkCParams(params.cParams) );
|
||||
memset(cctxParams, 0, sizeof(*cctxParams));
|
||||
cctxParams->cParams = params.cParams;
|
||||
cctxParams->fParams = params.fParams;
|
||||
cctxParams->compressionLevel = ZSTD_CLEVEL_CUSTOM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
|
||||
ZSTD_CCtx_params cctxParams, ZSTD_parameters params)
|
||||
{
|
||||
ZSTD_CCtx_params ret = cctxParams;
|
||||
ret.cParams = params.cParams;
|
||||
ret.fParams = params.fParams;
|
||||
return ret;
|
||||
if (cctx->compressionLevel==ZSTD_CLEVEL_CUSTOM) return;
|
||||
cctx->requestedParams.cParams = ZSTD_getCParams(cctx->compressionLevel,
|
||||
cctx->pledgedSrcSizePlusOne-1, 0);
|
||||
cctx->compressionLevel = ZSTD_CLEVEL_CUSTOM;
|
||||
}
|
||||
|
||||
#define CLAMPCHECK(val,min,max) { \
|
||||
@@ -254,253 +236,144 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
|
||||
{
|
||||
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
|
||||
|
||||
switch(param)
|
||||
{
|
||||
case ZSTD_p_compressionLevel:
|
||||
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||
|
||||
case ZSTD_p_windowLog:
|
||||
case ZSTD_p_hashLog:
|
||||
case ZSTD_p_chainLog:
|
||||
case ZSTD_p_searchLog:
|
||||
case ZSTD_p_minMatch:
|
||||
case ZSTD_p_targetLength:
|
||||
case ZSTD_p_compressionStrategy:
|
||||
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
ZSTD_cLevelToCParams(cctx); /* Can optimize if srcSize is known */
|
||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||
|
||||
case ZSTD_p_contentSizeFlag:
|
||||
case ZSTD_p_checksumFlag:
|
||||
case ZSTD_p_dictIDFlag:
|
||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||
|
||||
case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize,
|
||||
* even when referencing into Dictionary content
|
||||
* default : 0 when using a CDict, 1 when using a Prefix */
|
||||
cctx->loadedDictEnd = 0;
|
||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||
|
||||
case ZSTD_p_nbThreads:
|
||||
if (value==0) return 0;
|
||||
DEBUGLOG(5, " setting nbThreads : %u", value);
|
||||
if (value > 1 && cctx->staticSize) {
|
||||
return ERROR(parameter_unsupported); /* MT not compatible with static alloc */
|
||||
}
|
||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||
|
||||
case ZSTD_p_jobSize:
|
||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||
|
||||
case ZSTD_p_overlapSizeLog:
|
||||
DEBUGLOG(5, " setting overlap with nbThreads == %u", cctx->requestedParams.nbThreads);
|
||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||
|
||||
case ZSTD_p_enableLongDistanceMatching:
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
if (value != 0) {
|
||||
ZSTD_cLevelToCParams(cctx);
|
||||
}
|
||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||
|
||||
case ZSTD_p_ldmHashLog:
|
||||
case ZSTD_p_ldmMinMatch:
|
||||
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||
|
||||
case ZSTD_p_ldmBucketSizeLog:
|
||||
case ZSTD_p_ldmHashEveryLog:
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||
|
||||
default: return ERROR(parameter_unsupported);
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZSTD_CCtxParam_setParameter(
|
||||
ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case ZSTD_p_compressionLevel :
|
||||
if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel();
|
||||
if (value == 0) return 0;
|
||||
params->compressionLevel = value;
|
||||
if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel(); /* cap max compression level */
|
||||
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
cctx->compressionLevel = value;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_windowLog :
|
||||
if (value == 0) return 0;
|
||||
DEBUGLOG(5, "setting ZSTD_p_windowLog = %u (cdict:%u)",
|
||||
value, (cctx->cdict!=NULL));
|
||||
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
|
||||
ZSTD_cLevelToCCtxParams(params);
|
||||
params->cParams.windowLog = value;
|
||||
ZSTD_cLevelToCParams(cctx);
|
||||
cctx->requestedParams.cParams.windowLog = value;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_hashLog :
|
||||
if (value == 0) return 0;
|
||||
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
|
||||
ZSTD_cLevelToCCtxParams(params);
|
||||
params->cParams.hashLog = value;
|
||||
ZSTD_cLevelToCParams(cctx);
|
||||
cctx->requestedParams.cParams.hashLog = value;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_chainLog :
|
||||
if (value == 0) return 0;
|
||||
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
|
||||
ZSTD_cLevelToCCtxParams(params);
|
||||
params->cParams.chainLog = value;
|
||||
ZSTD_cLevelToCParams(cctx);
|
||||
cctx->requestedParams.cParams.chainLog = value;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_searchLog :
|
||||
if (value == 0) return 0;
|
||||
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
|
||||
ZSTD_cLevelToCCtxParams(params);
|
||||
params->cParams.searchLog = value;
|
||||
ZSTD_cLevelToCParams(cctx);
|
||||
cctx->requestedParams.cParams.searchLog = value;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_minMatch :
|
||||
if (value == 0) return 0;
|
||||
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
|
||||
ZSTD_cLevelToCCtxParams(params);
|
||||
params->cParams.searchLength = value;
|
||||
ZSTD_cLevelToCParams(cctx);
|
||||
cctx->requestedParams.cParams.searchLength = value;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_targetLength :
|
||||
if (value == 0) return 0;
|
||||
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
|
||||
ZSTD_cLevelToCCtxParams(params);
|
||||
params->cParams.targetLength = value;
|
||||
ZSTD_cLevelToCParams(cctx);
|
||||
cctx->requestedParams.cParams.targetLength = value;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_compressionStrategy :
|
||||
if (value == 0) return 0;
|
||||
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra);
|
||||
ZSTD_cLevelToCCtxParams(params);
|
||||
params->cParams.strategy = (ZSTD_strategy)value;
|
||||
ZSTD_cLevelToCParams(cctx);
|
||||
cctx->requestedParams.cParams.strategy = (ZSTD_strategy)value;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_contentSizeFlag :
|
||||
/* Content size written in frame header _when known_ (default:1) */
|
||||
DEBUGLOG(5, "set content size flag = %u", (value>0));
|
||||
params->fParams.contentSizeFlag = value > 0;
|
||||
/* Content size written in frame header _when known_ (default:1) */
|
||||
cctx->requestedParams.fParams.contentSizeFlag = value>0;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_checksumFlag :
|
||||
/* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
|
||||
params->fParams.checksumFlag = value > 0;
|
||||
cctx->requestedParams.fParams.checksumFlag = value>0;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
|
||||
DEBUGLOG(5, "set dictIDFlag = %u", (value>0));
|
||||
params->fParams.noDictIDFlag = (value == 0);
|
||||
cctx->requestedParams.fParams.noDictIDFlag = (value==0);
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_forceMaxWindow :
|
||||
params->forceWindow = value > 0;
|
||||
/* Dictionary parameters */
|
||||
case ZSTD_p_dictMode :
|
||||
if (cctx->cdict) return ERROR(stage_wrong); /* must be set before loading */
|
||||
/* restrict dictionary mode, to "rawContent" or "fullDict" only */
|
||||
ZSTD_STATIC_ASSERT((U32)ZSTD_dm_fullDict > (U32)ZSTD_dm_rawContent);
|
||||
if (value > (unsigned)ZSTD_dm_fullDict)
|
||||
return ERROR(parameter_outOfBound);
|
||||
cctx->dictMode = (ZSTD_dictMode_e)value;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_nbThreads :
|
||||
if (value == 0) return 0;
|
||||
case ZSTD_p_refDictContent :
|
||||
if (cctx->cdict) return ERROR(stage_wrong); /* must be set before loading */
|
||||
/* dictionary content will be referenced, instead of copied */
|
||||
cctx->dictContentByRef = value>0;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize,
|
||||
* even when referencing into Dictionary content
|
||||
* default : 0 when using a CDict, 1 when using a Prefix */
|
||||
cctx->forceWindow = value>0;
|
||||
cctx->loadedDictEnd = 0;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_nbThreads:
|
||||
if (value==0) return 0;
|
||||
DEBUGLOG(5, " setting nbThreads : %u", value);
|
||||
#ifndef ZSTD_MULTITHREAD
|
||||
if (value > 1) return ERROR(parameter_unsupported);
|
||||
return 0;
|
||||
#else
|
||||
return ZSTDMT_initializeCCtxParameters(params, value);
|
||||
#endif
|
||||
|
||||
case ZSTD_p_jobSize :
|
||||
#ifndef ZSTD_MULTITHREAD
|
||||
return ERROR(parameter_unsupported);
|
||||
#else
|
||||
if (params->nbThreads <= 1) return ERROR(parameter_unsupported);
|
||||
return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_sectionSize, value);
|
||||
#endif
|
||||
|
||||
case ZSTD_p_overlapSizeLog :
|
||||
#ifndef ZSTD_MULTITHREAD
|
||||
return ERROR(parameter_unsupported);
|
||||
#else
|
||||
if (params->nbThreads <= 1) return ERROR(parameter_unsupported);
|
||||
return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_overlapSectionLog, value);
|
||||
#endif
|
||||
|
||||
case ZSTD_p_enableLongDistanceMatching :
|
||||
if (value != 0) {
|
||||
ZSTD_cLevelToCCtxParams(params);
|
||||
params->cParams.windowLog = ZSTD_LDM_WINDOW_LOG;
|
||||
if ((value>1) && (cctx->nbThreads != value)) {
|
||||
if (cctx->staticSize) /* MT not compatible with static alloc */
|
||||
return ERROR(parameter_unsupported);
|
||||
ZSTDMT_freeCCtx(cctx->mtctx);
|
||||
cctx->nbThreads = 1;
|
||||
cctx->mtctx = ZSTDMT_createCCtx_advanced(value, cctx->customMem);
|
||||
if (cctx->mtctx == NULL) return ERROR(memory_allocation);
|
||||
}
|
||||
return ZSTD_ldm_initializeParameters(¶ms->ldmParams, value);
|
||||
|
||||
case ZSTD_p_ldmHashLog :
|
||||
if (value == 0) return 0;
|
||||
CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
|
||||
params->ldmParams.hashLog = value;
|
||||
cctx->nbThreads = value;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_ldmMinMatch :
|
||||
if (value == 0) return 0;
|
||||
CLAMPCHECK(value, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX);
|
||||
params->ldmParams.minMatchLength = value;
|
||||
return 0;
|
||||
case ZSTD_p_jobSize:
|
||||
if (cctx->nbThreads <= 1) return ERROR(parameter_unsupported);
|
||||
assert(cctx->mtctx != NULL);
|
||||
return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_sectionSize, value);
|
||||
|
||||
case ZSTD_p_ldmBucketSizeLog :
|
||||
if (value > ZSTD_LDM_BUCKETSIZELOG_MAX) {
|
||||
return ERROR(parameter_outOfBound);
|
||||
}
|
||||
params->ldmParams.bucketSizeLog = value;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_ldmHashEveryLog :
|
||||
if (value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN) {
|
||||
return ERROR(parameter_outOfBound);
|
||||
}
|
||||
params->ldmParams.hashEveryLog = value;
|
||||
return 0;
|
||||
case ZSTD_p_overlapSizeLog:
|
||||
DEBUGLOG(5, " setting overlap with nbThreads == %u", cctx->nbThreads);
|
||||
if (cctx->nbThreads <= 1) return ERROR(parameter_unsupported);
|
||||
assert(cctx->mtctx != NULL);
|
||||
return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_overlapSectionLog, value);
|
||||
|
||||
default: return ERROR(parameter_unsupported);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function should be updated whenever ZSTD_CCtx_params is updated.
|
||||
* Parameters are copied manually before the dictionary is loaded.
|
||||
* The multithreading parameters jobSize and overlapSizeLog are set only if
|
||||
* nbThreads > 1.
|
||||
*
|
||||
* Pledged srcSize is treated as unknown.
|
||||
*/
|
||||
size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
||||
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
|
||||
{
|
||||
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
|
||||
/* Assume the compression and frame parameters are validated */
|
||||
cctx->requestedParams.cParams = params->cParams;
|
||||
cctx->requestedParams.fParams = params->fParams;
|
||||
cctx->requestedParams.compressionLevel = params->compressionLevel;
|
||||
|
||||
/* Set force window explicitly since it sets cctx->loadedDictEnd */
|
||||
CHECK_F( ZSTD_CCtx_setParameter(
|
||||
cctx, ZSTD_p_forceMaxWindow, params->forceWindow) );
|
||||
|
||||
/* Set multithreading parameters explicitly */
|
||||
CHECK_F( ZSTD_CCtx_setParameter(cctx, ZSTD_p_nbThreads, params->nbThreads) );
|
||||
if (params->nbThreads > 1) {
|
||||
CHECK_F( ZSTD_CCtx_setParameter(cctx, ZSTD_p_jobSize, params->jobSize) );
|
||||
CHECK_F( ZSTD_CCtx_setParameter(
|
||||
cctx, ZSTD_p_overlapSizeLog, params->overlapSizeLog) );
|
||||
}
|
||||
|
||||
/* Copy long distance matching parameters */
|
||||
cctx->requestedParams.ldmParams = params->ldmParams;
|
||||
|
||||
/* customMem is used only for create/free params and can be ignored */
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
|
||||
{
|
||||
DEBUGLOG(5, " setting pledgedSrcSize to %u", (U32)pledgedSrcSize);
|
||||
@@ -509,9 +382,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ZSTD_CCtx_loadDictionary_advanced(
|
||||
ZSTD_CCtx* cctx, const void* dict, size_t dictSize,
|
||||
ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode)
|
||||
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
|
||||
{
|
||||
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
|
||||
if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */
|
||||
@@ -522,10 +393,12 @@ size_t ZSTD_CCtx_loadDictionary_advanced(
|
||||
cctx->cdict = NULL;
|
||||
} else {
|
||||
ZSTD_compressionParameters const cParams =
|
||||
ZSTD_getCParamsFromCCtxParams(cctx->requestedParams, 0, dictSize);
|
||||
cctx->compressionLevel == ZSTD_CLEVEL_CUSTOM ?
|
||||
cctx->requestedParams.cParams :
|
||||
ZSTD_getCParams(cctx->compressionLevel, 0, dictSize);
|
||||
cctx->cdictLocal = ZSTD_createCDict_advanced(
|
||||
dict, dictSize,
|
||||
dictLoadMethod, dictMode,
|
||||
cctx->dictContentByRef, cctx->dictMode,
|
||||
cParams, cctx->customMem);
|
||||
cctx->cdict = cctx->cdictLocal;
|
||||
if (cctx->cdictLocal == NULL)
|
||||
@@ -534,41 +407,21 @@ size_t ZSTD_CCtx_loadDictionary_advanced(
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(
|
||||
ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
|
||||
{
|
||||
return ZSTD_CCtx_loadDictionary_advanced(
|
||||
cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dm_auto);
|
||||
}
|
||||
|
||||
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
|
||||
{
|
||||
return ZSTD_CCtx_loadDictionary_advanced(
|
||||
cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dm_auto);
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
|
||||
{
|
||||
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
|
||||
cctx->cdict = cdict;
|
||||
memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* exclusive */
|
||||
cctx->prefix = NULL; /* exclusive */
|
||||
cctx->prefixSize = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
|
||||
{
|
||||
return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dm_rawContent);
|
||||
}
|
||||
|
||||
size_t ZSTD_CCtx_refPrefix_advanced(
|
||||
ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode)
|
||||
{
|
||||
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
|
||||
cctx->cdict = NULL; /* prefix discards any prior cdict */
|
||||
cctx->prefixDict.dict = prefix;
|
||||
cctx->prefixDict.dictSize = prefixSize;
|
||||
cctx->prefixDict.dictMode = dictMode;
|
||||
cctx->prefix = prefix;
|
||||
cctx->prefixSize = prefixSize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -644,8 +497,7 @@ ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameter
|
||||
{ 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);
|
||||
U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
|
||||
if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
|
||||
} }
|
||||
if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
|
||||
@@ -664,81 +516,56 @@ 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_advanced(ZSTD_compressionParameters cParams)
|
||||
{
|
||||
/* Estimate CCtx size is supported for single-threaded compression only. */
|
||||
if (params->nbThreads > 1) { return ERROR(GENERIC); }
|
||||
{ ZSTD_compressionParameters const cParams =
|
||||
ZSTD_getCParamsFromCCtxParams(*params, 0, 0);
|
||||
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
|
||||
U32 const divider = (cParams.searchLength==3) ? 3 : 4;
|
||||
size_t const maxNbSeq = blockSize / divider;
|
||||
size_t const tokenSpace = blockSize + 11*maxNbSeq;
|
||||
size_t const chainSize =
|
||||
(cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
|
||||
size_t const hSize = ((size_t)1) << cParams.hashLog;
|
||||
U32 const hashLog3 = (cParams.searchLength>3) ?
|
||||
0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
|
||||
size_t const h3Size = ((size_t)1) << hashLog3;
|
||||
size_t const entropySpace = sizeof(ZSTD_entropyCTables_t);
|
||||
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
|
||||
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
|
||||
U32 const divider = (cParams.searchLength==3) ? 3 : 4;
|
||||
size_t const maxNbSeq = blockSize / divider;
|
||||
size_t const tokenSpace = blockSize + 11*maxNbSeq;
|
||||
|
||||
size_t const optBudget =
|
||||
((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
|
||||
+ (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
|
||||
size_t const optSpace = ((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btultra)) ? optBudget : 0;
|
||||
size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
|
||||
size_t const hSize = ((size_t)1) << cParams.hashLog;
|
||||
U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
|
||||
size_t const h3Size = ((size_t)1) << hashLog3;
|
||||
size_t const entropySpace = sizeof(ZSTD_entropyCTables_t);
|
||||
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
|
||||
|
||||
size_t const ldmSpace = params->ldmParams.enableLdm ?
|
||||
ZSTD_ldm_getTableSize(params->ldmParams.hashLog,
|
||||
params->ldmParams.bucketSizeLog) : 0;
|
||||
size_t const optBudget = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
|
||||
+ (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
|
||||
size_t const optSpace = ((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btultra)) ? optBudget : 0;
|
||||
size_t const neededSpace = entropySpace + tableSpace + tokenSpace + optSpace;
|
||||
|
||||
size_t const neededSpace = entropySpace + tableSpace + tokenSpace +
|
||||
optSpace + ldmSpace;
|
||||
|
||||
DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx));
|
||||
DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace);
|
||||
return sizeof(ZSTD_CCtx) + neededSpace;
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCCtxSize_advanced_usingCParams(ZSTD_compressionParameters cParams)
|
||||
{
|
||||
ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
|
||||
return ZSTD_estimateCCtxSize_advanced_usingCCtxParams(¶ms);
|
||||
DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx));
|
||||
DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace);
|
||||
return sizeof(ZSTD_CCtx) + neededSpace;
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCCtxSize(int compressionLevel)
|
||||
{
|
||||
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
|
||||
return ZSTD_estimateCCtxSize_advanced_usingCParams(cParams);
|
||||
return ZSTD_estimateCCtxSize_advanced(cParams);
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params)
|
||||
size_t ZSTD_estimateCStreamSize_advanced(ZSTD_compressionParameters cParams)
|
||||
{
|
||||
if (params->nbThreads > 1) { return ERROR(GENERIC); }
|
||||
{ size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced_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;
|
||||
size_t const streamingSize = inBuffSize + outBuffSize;
|
||||
size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced(cParams);
|
||||
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
|
||||
size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
|
||||
size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
|
||||
size_t const streamingSize = inBuffSize + outBuffSize;
|
||||
|
||||
return CCtxSize + streamingSize;
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCStreamSize_advanced_usingCParams(ZSTD_compressionParameters cParams)
|
||||
{
|
||||
ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
|
||||
return ZSTD_estimateCStreamSize_advanced_usingCCtxParams(¶ms);
|
||||
return CCtxSize + streamingSize;
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCStreamSize(int compressionLevel) {
|
||||
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
|
||||
return ZSTD_estimateCStreamSize_advanced_usingCParams(cParams);
|
||||
return ZSTD_estimateCStreamSize_advanced(cParams);
|
||||
}
|
||||
|
||||
static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
|
||||
ZSTD_compressionParameters cParams2)
|
||||
|
||||
static U32 ZSTD_equivalentParams(ZSTD_compressionParameters cParams1,
|
||||
ZSTD_compressionParameters cParams2)
|
||||
{
|
||||
U32 bslog1 = MIN(cParams1.windowLog, ZSTD_BLOCKSIZELOG_MAX);
|
||||
U32 bslog2 = MIN(cParams2.windowLog, ZSTD_BLOCKSIZELOG_MAX);
|
||||
@@ -749,30 +576,9 @@ static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
|
||||
& ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */
|
||||
}
|
||||
|
||||
/** The parameters are equivalent if ldm is not enabled in both sets or
|
||||
* all the parameters are equivalent. */
|
||||
static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1,
|
||||
ldmParams_t ldmParams2)
|
||||
{
|
||||
return (!ldmParams1.enableLdm && !ldmParams2.enableLdm) ||
|
||||
(ldmParams1.enableLdm == ldmParams2.enableLdm &&
|
||||
ldmParams1.hashLog == ldmParams2.hashLog &&
|
||||
ldmParams1.bucketSizeLog == ldmParams2.bucketSizeLog &&
|
||||
ldmParams1.minMatchLength == ldmParams2.minMatchLength &&
|
||||
ldmParams1.hashEveryLog == ldmParams2.hashEveryLog);
|
||||
}
|
||||
|
||||
/** Equivalence for resetCCtx purposes */
|
||||
static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
|
||||
ZSTD_CCtx_params params2)
|
||||
{
|
||||
return ZSTD_equivalentCParams(params1.cParams, params2.cParams) &&
|
||||
ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams);
|
||||
}
|
||||
|
||||
/*! ZSTD_continueCCtx() :
|
||||
* reuse CCtx without reset (note : requires no dictionary) */
|
||||
static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize)
|
||||
static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 pledgedSrcSize)
|
||||
{
|
||||
U32 const end = (U32)(cctx->nextSrc - cctx->base);
|
||||
DEBUGLOG(5, "continue mode");
|
||||
@@ -801,17 +607,15 @@ typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e;
|
||||
/*! ZSTD_resetCCtx_internal() :
|
||||
note : `params` are assumed fully validated at this stage */
|
||||
static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
ZSTD_CCtx_params params, U64 pledgedSrcSize,
|
||||
ZSTD_parameters params, U64 pledgedSrcSize,
|
||||
ZSTD_compResetPolicy_e const crp,
|
||||
ZSTD_buffered_policy_e const zbuff)
|
||||
{
|
||||
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
|
||||
|
||||
if (crp == ZSTDcrp_continue) {
|
||||
if (ZSTD_equivalentParams(params, zc->appliedParams)) {
|
||||
if (ZSTD_equivalentParams(params.cParams, zc->appliedParams.cParams)) {
|
||||
DEBUGLOG(5, "ZSTD_equivalentParams()==1");
|
||||
assert(!(params.ldmParams.enableLdm &&
|
||||
params.ldmParams.hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET));
|
||||
zc->entropy->hufCTable_repeatMode = HUF_repeat_none;
|
||||
zc->entropy->offcode_repeatMode = FSE_repeat_none;
|
||||
zc->entropy->matchlength_repeatMode = FSE_repeat_none;
|
||||
@@ -819,15 +623,6 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
|
||||
} }
|
||||
|
||||
if (params.ldmParams.enableLdm) {
|
||||
/* Adjust long distance matching parameters */
|
||||
ZSTD_ldm_adjustParameters(¶ms.ldmParams, params.cParams.windowLog);
|
||||
assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
|
||||
assert(params.ldmParams.hashEveryLog < 32);
|
||||
zc->ldmState.hashPower =
|
||||
ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength);
|
||||
}
|
||||
|
||||
{ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
|
||||
U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
|
||||
size_t const maxNbSeq = blockSize / divider;
|
||||
@@ -851,13 +646,10 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
|| (params.cParams.strategy == ZSTD_btultra)) ?
|
||||
optPotentialSpace : 0;
|
||||
size_t const bufferSpace = buffInSize + buffOutSize;
|
||||
size_t const ldmSpace = params.ldmParams.enableLdm
|
||||
? ZSTD_ldm_getTableSize(params.ldmParams.hashLog, params.ldmParams.bucketSizeLog)
|
||||
: 0;
|
||||
size_t const neededSpace = entropySpace + optSpace + ldmSpace +
|
||||
tableSpace + tokenSpace + bufferSpace;
|
||||
size_t const neededSpace = entropySpace + optSpace + tableSpace
|
||||
+ tokenSpace + bufferSpace;
|
||||
|
||||
if (zc->workSpaceSize < neededSpace) { /* too small : resize */
|
||||
if (zc->workSpaceSize < neededSpace) { /* too small : resize /*/
|
||||
DEBUGLOG(5, "Need to update workSpaceSize from %uK to %uK \n",
|
||||
(unsigned)zc->workSpaceSize>>10,
|
||||
(unsigned)neededSpace>>10);
|
||||
@@ -922,16 +714,6 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
ptr = zc->optState.priceTable + ZSTD_OPT_NUM+1;
|
||||
}
|
||||
|
||||
/* ldm hash table */
|
||||
/* initialize bucketOffsets table later for pointer alignment */
|
||||
if (params.ldmParams.enableLdm) {
|
||||
size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
|
||||
memset(ptr, 0, ldmHSize * sizeof(ldmEntry_t));
|
||||
assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
|
||||
zc->ldmState.hashTable = (ldmEntry_t*)ptr;
|
||||
ptr = zc->ldmState.hashTable + ldmHSize;
|
||||
}
|
||||
|
||||
/* table Space */
|
||||
if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
|
||||
assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
|
||||
@@ -949,16 +731,6 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
|
||||
ptr = zc->seqStore.litStart + blockSize;
|
||||
|
||||
/* ldm bucketOffsets table */
|
||||
if (params.ldmParams.enableLdm) {
|
||||
size_t const ldmBucketSize =
|
||||
((size_t)1) << (params.ldmParams.hashLog -
|
||||
params.ldmParams.bucketSizeLog);
|
||||
memset(ptr, 0, ldmBucketSize);
|
||||
zc->ldmState.bucketOffsets = (BYTE*)ptr;
|
||||
ptr = zc->ldmState.bucketOffsets + ldmBucketSize;
|
||||
}
|
||||
|
||||
/* buffers */
|
||||
zc->inBuffSize = buffInSize;
|
||||
zc->inBuff = (char*)ptr;
|
||||
@@ -981,8 +753,6 @@ void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
|
||||
|
||||
/*! ZSTD_copyCCtx_internal() :
|
||||
* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
|
||||
* The "context", in this case, refers to the hash and chain tables, entropy
|
||||
* tables, and dictionary offsets.
|
||||
* Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
|
||||
* pledgedSrcSize=0 means "empty" if fParams.contentSizeFlag=1
|
||||
* @return : 0, or an error code */
|
||||
@@ -996,9 +766,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
|
||||
if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
|
||||
|
||||
memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
|
||||
{ ZSTD_CCtx_params params = dstCCtx->requestedParams;
|
||||
/* Copy only compression parameters related to tables. */
|
||||
params.cParams = srcCCtx->appliedParams.cParams;
|
||||
{ ZSTD_parameters params = srcCCtx->appliedParams;
|
||||
params.fParams = fParams;
|
||||
ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
|
||||
ZSTDcrp_noMemset, zbuff);
|
||||
@@ -1058,36 +826,18 @@ static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reduce
|
||||
}
|
||||
}
|
||||
|
||||
/*! ZSTD_ldm_reduceTable() :
|
||||
* reduce table indexes by `reducerValue` */
|
||||
static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size,
|
||||
U32 const reducerValue)
|
||||
{
|
||||
U32 u;
|
||||
for (u = 0; u < size; u++) {
|
||||
if (table[u].offset < reducerValue) table[u].offset = 0;
|
||||
else table[u].offset -= reducerValue;
|
||||
}
|
||||
}
|
||||
|
||||
/*! ZSTD_reduceIndex() :
|
||||
* rescale all indexes to avoid future overflow (indexes are U32) */
|
||||
static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
|
||||
{
|
||||
{ U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog;
|
||||
{ U32 const hSize = 1 << zc->appliedParams.cParams.hashLog;
|
||||
ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
|
||||
|
||||
{ U32 const chainSize = (zc->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((U32)1 << zc->appliedParams.cParams.chainLog);
|
||||
{ U32 const chainSize = (zc->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->appliedParams.cParams.chainLog);
|
||||
ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
|
||||
|
||||
{ U32 const h3Size = (zc->hashLog3) ? (U32)1 << zc->hashLog3 : 0;
|
||||
{ U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
|
||||
ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
|
||||
|
||||
{ if (zc->appliedParams.ldmParams.enableLdm) {
|
||||
U32 const ldmHSize = (U32)1 << zc->appliedParams.ldmParams.hashLog;
|
||||
ZSTD_ldm_reduceTable(zc->ldmState.hashTable, ldmHSize, reducerValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1226,6 +976,24 @@ static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t * entropy,
|
||||
return lhSize+cLitSize;
|
||||
}
|
||||
|
||||
static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 16, 17, 17, 18, 18, 19, 19,
|
||||
20, 20, 20, 20, 21, 21, 21, 21,
|
||||
22, 22, 22, 22, 22, 22, 22, 22,
|
||||
23, 23, 23, 23, 23, 23, 23, 23,
|
||||
24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24 };
|
||||
|
||||
static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
|
||||
38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
|
||||
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
|
||||
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
|
||||
|
||||
|
||||
void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
|
||||
{
|
||||
@@ -1363,7 +1131,7 @@ MEM_STATIC size_t ZSTD_encodeSequences(void* dst, size_t dstCapacity,
|
||||
BIT_addBits(&blockStream, sequences[n].litLength, llBits);
|
||||
if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
|
||||
BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
|
||||
if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream);
|
||||
if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
|
||||
if (longOffsets) {
|
||||
int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
|
||||
if (extraBits) {
|
||||
@@ -1511,11 +1279,1528 @@ MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
|
||||
return cSize;
|
||||
}
|
||||
|
||||
|
||||
/*! ZSTD_storeSeq() :
|
||||
Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
|
||||
`offsetCode` : distance to match, or 0 == repCode.
|
||||
`matchCode` : matchLength - MINMATCH
|
||||
*/
|
||||
MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode)
|
||||
{
|
||||
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6)
|
||||
static const BYTE* g_start = NULL;
|
||||
U32 const pos = (U32)((const BYTE*)literals - g_start);
|
||||
if (g_start==NULL) g_start = (const BYTE*)literals;
|
||||
if ((pos > 0) && (pos < 1000000000))
|
||||
DEBUGLOG(6, "Cpos %6u :%5u literals & match %3u bytes at distance %6u",
|
||||
pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
|
||||
#endif
|
||||
/* copy Literals */
|
||||
assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + 128 KB);
|
||||
ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
|
||||
seqStorePtr->lit += litLength;
|
||||
|
||||
/* literal Length */
|
||||
if (litLength>0xFFFF) {
|
||||
seqStorePtr->longLengthID = 1;
|
||||
seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
|
||||
}
|
||||
seqStorePtr->sequences[0].litLength = (U16)litLength;
|
||||
|
||||
/* match offset */
|
||||
seqStorePtr->sequences[0].offset = offsetCode + 1;
|
||||
|
||||
/* match Length */
|
||||
if (matchCode>0xFFFF) {
|
||||
seqStorePtr->longLengthID = 2;
|
||||
seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
|
||||
}
|
||||
seqStorePtr->sequences[0].matchLength = (U16)matchCode;
|
||||
|
||||
seqStorePtr->sequences++;
|
||||
}
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Match length counter
|
||||
***************************************/
|
||||
static unsigned ZSTD_NbCommonBytes (register size_t val)
|
||||
{
|
||||
if (MEM_isLittleEndian()) {
|
||||
if (MEM_64bits()) {
|
||||
# if defined(_MSC_VER) && defined(_WIN64)
|
||||
unsigned long r = 0;
|
||||
_BitScanForward64( &r, (U64)val );
|
||||
return (unsigned)(r>>3);
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 3)
|
||||
return (__builtin_ctzll((U64)val) >> 3);
|
||||
# else
|
||||
static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
|
||||
0, 3, 1, 3, 1, 4, 2, 7,
|
||||
0, 2, 3, 6, 1, 5, 3, 5,
|
||||
1, 3, 4, 4, 2, 5, 6, 7,
|
||||
7, 0, 1, 2, 3, 3, 4, 6,
|
||||
2, 6, 5, 5, 3, 4, 5, 6,
|
||||
7, 1, 2, 4, 6, 4, 4, 5,
|
||||
7, 2, 6, 5, 7, 6, 7, 7 };
|
||||
return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
|
||||
# endif
|
||||
} else { /* 32 bits */
|
||||
# if defined(_MSC_VER)
|
||||
unsigned long r=0;
|
||||
_BitScanForward( &r, (U32)val );
|
||||
return (unsigned)(r>>3);
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 3)
|
||||
return (__builtin_ctz((U32)val) >> 3);
|
||||
# else
|
||||
static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
|
||||
3, 2, 2, 1, 3, 2, 0, 1,
|
||||
3, 3, 1, 2, 2, 2, 2, 0,
|
||||
3, 1, 2, 0, 1, 0, 1, 1 };
|
||||
return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
|
||||
# endif
|
||||
}
|
||||
} else { /* Big Endian CPU */
|
||||
if (MEM_64bits()) {
|
||||
# if defined(_MSC_VER) && defined(_WIN64)
|
||||
unsigned long r = 0;
|
||||
_BitScanReverse64( &r, val );
|
||||
return (unsigned)(r>>3);
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 3)
|
||||
return (__builtin_clzll(val) >> 3);
|
||||
# else
|
||||
unsigned r;
|
||||
const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
|
||||
if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
|
||||
if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
|
||||
r += (!val);
|
||||
return r;
|
||||
# endif
|
||||
} else { /* 32 bits */
|
||||
# if defined(_MSC_VER)
|
||||
unsigned long r = 0;
|
||||
_BitScanReverse( &r, (unsigned long)val );
|
||||
return (unsigned)(r>>3);
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 3)
|
||||
return (__builtin_clz((U32)val) >> 3);
|
||||
# else
|
||||
unsigned r;
|
||||
if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
|
||||
r += (!val);
|
||||
return r;
|
||||
# endif
|
||||
} }
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
|
||||
{
|
||||
const BYTE* const pStart = pIn;
|
||||
const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
|
||||
|
||||
while (pIn < pInLoopLimit) {
|
||||
size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
|
||||
if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
|
||||
pIn += ZSTD_NbCommonBytes(diff);
|
||||
return (size_t)(pIn - pStart);
|
||||
}
|
||||
if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
|
||||
if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
|
||||
if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
|
||||
return (size_t)(pIn - pStart);
|
||||
}
|
||||
|
||||
/** ZSTD_count_2segments() :
|
||||
* can count match length with `ip` & `match` in 2 different segments.
|
||||
* convention : on reaching mEnd, match count continue starting from iStart
|
||||
*/
|
||||
static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
|
||||
{
|
||||
const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
|
||||
size_t const matchLength = ZSTD_count(ip, match, vEnd);
|
||||
if (match + matchLength != mEnd) return matchLength;
|
||||
return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
|
||||
}
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Hashes
|
||||
***************************************/
|
||||
static const U32 prime3bytes = 506832829U;
|
||||
static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
|
||||
MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
|
||||
|
||||
static const U32 prime4bytes = 2654435761U;
|
||||
static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
|
||||
static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
|
||||
|
||||
static const U64 prime5bytes = 889523592379ULL;
|
||||
static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
|
||||
|
||||
static const U64 prime6bytes = 227718039650203ULL;
|
||||
static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
|
||||
|
||||
static const U64 prime7bytes = 58295818150454627ULL;
|
||||
static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
|
||||
|
||||
static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
|
||||
static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
|
||||
|
||||
static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
|
||||
{
|
||||
switch(mls)
|
||||
{
|
||||
default:
|
||||
case 4: return ZSTD_hash4Ptr(p, hBits);
|
||||
case 5: return ZSTD_hash5Ptr(p, hBits);
|
||||
case 6: return ZSTD_hash6Ptr(p, hBits);
|
||||
case 7: return ZSTD_hash7Ptr(p, hBits);
|
||||
case 8: return ZSTD_hash8Ptr(p, hBits);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Fast Scan
|
||||
***************************************/
|
||||
static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
|
||||
{
|
||||
U32* const hashTable = zc->hashTable;
|
||||
U32 const hBits = zc->appliedParams.cParams.hashLog;
|
||||
const BYTE* const base = zc->base;
|
||||
const BYTE* ip = base + zc->nextToUpdate;
|
||||
const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
|
||||
const size_t fastHashFillStep = 3;
|
||||
|
||||
while(ip <= iend) {
|
||||
hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
|
||||
ip += fastHashFillStep;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
|
||||
const void* src, size_t srcSize,
|
||||
const U32 mls)
|
||||
{
|
||||
U32* const hashTable = cctx->hashTable;
|
||||
U32 const hBits = cctx->appliedParams.cParams.hashLog;
|
||||
seqStore_t* seqStorePtr = &(cctx->seqStore);
|
||||
const BYTE* const base = cctx->base;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 lowestIndex = cctx->dictLimit;
|
||||
const BYTE* const lowest = base + lowestIndex;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - HASH_READ_SIZE;
|
||||
U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
|
||||
U32 offsetSaved = 0;
|
||||
|
||||
/* init */
|
||||
ip += (ip==lowest);
|
||||
{ U32 const maxRep = (U32)(ip-lowest);
|
||||
if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
|
||||
if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
|
||||
}
|
||||
|
||||
/* Main Search Loop */
|
||||
while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
|
||||
size_t mLength;
|
||||
size_t const h = ZSTD_hashPtr(ip, hBits, mls);
|
||||
U32 const current = (U32)(ip-base);
|
||||
U32 const matchIndex = hashTable[h];
|
||||
const BYTE* match = base + matchIndex;
|
||||
hashTable[h] = current; /* update hash table */
|
||||
|
||||
if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
|
||||
mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
|
||||
ip++;
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||
} else {
|
||||
U32 offset;
|
||||
if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
|
||||
ip += ((ip-anchor) >> g_searchStrength) + 1;
|
||||
continue;
|
||||
}
|
||||
mLength = ZSTD_count(ip+4, match+4, iend) + 4;
|
||||
offset = (U32)(ip-match);
|
||||
while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
}
|
||||
|
||||
/* match found */
|
||||
ip += mLength;
|
||||
anchor = ip;
|
||||
|
||||
if (ip <= ilimit) {
|
||||
/* Fill Table */
|
||||
hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2; /* here because current+2 could be > iend-8 */
|
||||
hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
|
||||
/* check immediate repcode */
|
||||
while ( (ip <= ilimit)
|
||||
&& ( (offset_2>0)
|
||||
& (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
|
||||
/* store sequence */
|
||||
size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
||||
{ U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
|
||||
hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
|
||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
|
||||
ip += rLength;
|
||||
anchor = ip;
|
||||
continue; /* faster when present ... (?) */
|
||||
} } }
|
||||
|
||||
/* save reps for next block */
|
||||
seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
|
||||
seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
|
||||
|
||||
/* Last Literals */
|
||||
{ size_t const lastLLSize = iend - anchor;
|
||||
memcpy(seqStorePtr->lit, anchor, lastLLSize);
|
||||
seqStorePtr->lit += lastLLSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
const U32 mls = ctx->appliedParams.cParams.searchLength;
|
||||
switch(mls)
|
||||
{
|
||||
default: /* includes case 3 */
|
||||
case 4 :
|
||||
ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
|
||||
case 5 :
|
||||
ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
|
||||
case 6 :
|
||||
ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
|
||||
case 7 :
|
||||
ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize,
|
||||
const U32 mls)
|
||||
{
|
||||
U32* hashTable = ctx->hashTable;
|
||||
const U32 hBits = ctx->appliedParams.cParams.hashLog;
|
||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
||||
const BYTE* const base = ctx->base;
|
||||
const BYTE* const dictBase = ctx->dictBase;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 lowestIndex = ctx->lowLimit;
|
||||
const BYTE* const dictStart = dictBase + lowestIndex;
|
||||
const U32 dictLimit = ctx->dictLimit;
|
||||
const BYTE* const lowPrefixPtr = base + dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
|
||||
|
||||
/* Search Loop */
|
||||
while (ip < ilimit) { /* < instead of <=, because (ip+1) */
|
||||
const size_t h = ZSTD_hashPtr(ip, hBits, mls);
|
||||
const U32 matchIndex = hashTable[h];
|
||||
const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* match = matchBase + matchIndex;
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
|
||||
const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* repMatch = repBase + repIndex;
|
||||
size_t mLength;
|
||||
hashTable[h] = current; /* update hash table */
|
||||
|
||||
if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
|
||||
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
||||
const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
|
||||
ip++;
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||
} else {
|
||||
if ( (matchIndex < lowestIndex) ||
|
||||
(MEM_read32(match) != MEM_read32(ip)) ) {
|
||||
ip += ((ip-anchor) >> g_searchStrength) + 1;
|
||||
continue;
|
||||
}
|
||||
{ const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
|
||||
const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
|
||||
U32 offset;
|
||||
mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
|
||||
while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
offset = current - matchIndex;
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
} }
|
||||
|
||||
/* found a match : store it */
|
||||
ip += mLength;
|
||||
anchor = ip;
|
||||
|
||||
if (ip <= ilimit) {
|
||||
/* Fill Table */
|
||||
hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
|
||||
hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
|
||||
/* check immediate repcode */
|
||||
while (ip <= ilimit) {
|
||||
U32 const current2 = (U32)(ip-base);
|
||||
U32 const repIndex2 = current2 - offset_2;
|
||||
const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
|
||||
if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
|
||||
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
||||
const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
|
||||
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
|
||||
U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
|
||||
hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
|
||||
ip += repLength2;
|
||||
anchor = ip;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} } }
|
||||
|
||||
/* save reps for next block */
|
||||
seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
|
||||
|
||||
/* Last Literals */
|
||||
{ size_t const lastLLSize = iend - anchor;
|
||||
memcpy(seqStorePtr->lit, anchor, lastLLSize);
|
||||
seqStorePtr->lit += lastLLSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
U32 const mls = ctx->appliedParams.cParams.searchLength;
|
||||
switch(mls)
|
||||
{
|
||||
default: /* includes case 3 */
|
||||
case 4 :
|
||||
ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
|
||||
case 5 :
|
||||
ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
|
||||
case 6 :
|
||||
ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
|
||||
case 7 :
|
||||
ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Double Fast
|
||||
***************************************/
|
||||
static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
|
||||
{
|
||||
U32* const hashLarge = cctx->hashTable;
|
||||
U32 const hBitsL = cctx->appliedParams.cParams.hashLog;
|
||||
U32* const hashSmall = cctx->chainTable;
|
||||
U32 const hBitsS = cctx->appliedParams.cParams.chainLog;
|
||||
const BYTE* const base = cctx->base;
|
||||
const BYTE* ip = base + cctx->nextToUpdate;
|
||||
const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
|
||||
const size_t fastHashFillStep = 3;
|
||||
|
||||
while(ip <= iend) {
|
||||
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
|
||||
hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
|
||||
ip += fastHashFillStep;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
|
||||
const void* src, size_t srcSize,
|
||||
const U32 mls)
|
||||
{
|
||||
U32* const hashLong = cctx->hashTable;
|
||||
const U32 hBitsL = cctx->appliedParams.cParams.hashLog;
|
||||
U32* const hashSmall = cctx->chainTable;
|
||||
const U32 hBitsS = cctx->appliedParams.cParams.chainLog;
|
||||
seqStore_t* seqStorePtr = &(cctx->seqStore);
|
||||
const BYTE* const base = cctx->base;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 lowestIndex = cctx->dictLimit;
|
||||
const BYTE* const lowest = base + lowestIndex;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - HASH_READ_SIZE;
|
||||
U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
|
||||
U32 offsetSaved = 0;
|
||||
|
||||
/* init */
|
||||
ip += (ip==lowest);
|
||||
{ U32 const maxRep = (U32)(ip-lowest);
|
||||
if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
|
||||
if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
|
||||
}
|
||||
|
||||
/* Main Search Loop */
|
||||
while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
|
||||
size_t mLength;
|
||||
size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
|
||||
size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
|
||||
U32 const current = (U32)(ip-base);
|
||||
U32 const matchIndexL = hashLong[h2];
|
||||
U32 const matchIndexS = hashSmall[h];
|
||||
const BYTE* matchLong = base + matchIndexL;
|
||||
const BYTE* match = base + matchIndexS;
|
||||
hashLong[h2] = hashSmall[h] = current; /* update hash tables */
|
||||
|
||||
assert(offset_1 <= current); /* supposed guaranteed by construction */
|
||||
if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
|
||||
/* favor repcode */
|
||||
mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
|
||||
ip++;
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||
} else {
|
||||
U32 offset;
|
||||
if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
|
||||
mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
|
||||
offset = (U32)(ip-matchLong);
|
||||
while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
|
||||
} else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
|
||||
size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
|
||||
U32 const matchIndexL3 = hashLong[hl3];
|
||||
const BYTE* matchL3 = base + matchIndexL3;
|
||||
hashLong[hl3] = current + 1;
|
||||
if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
|
||||
mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
|
||||
ip++;
|
||||
offset = (U32)(ip-matchL3);
|
||||
while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
|
||||
} else {
|
||||
mLength = ZSTD_count(ip+4, match+4, iend) + 4;
|
||||
offset = (U32)(ip-match);
|
||||
while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
}
|
||||
} else {
|
||||
ip += ((ip-anchor) >> g_searchStrength) + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
}
|
||||
|
||||
/* match found */
|
||||
ip += mLength;
|
||||
anchor = ip;
|
||||
|
||||
if (ip <= ilimit) {
|
||||
/* Fill Table */
|
||||
hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
|
||||
hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
|
||||
hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
|
||||
hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
|
||||
|
||||
/* check immediate repcode */
|
||||
while ( (ip <= ilimit)
|
||||
&& ( (offset_2>0)
|
||||
& (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
|
||||
/* store sequence */
|
||||
size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
||||
{ U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
|
||||
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
|
||||
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
|
||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
|
||||
ip += rLength;
|
||||
anchor = ip;
|
||||
continue; /* faster when present ... (?) */
|
||||
} } }
|
||||
|
||||
/* save reps for next block */
|
||||
seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
|
||||
seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
|
||||
|
||||
/* Last Literals */
|
||||
{ size_t const lastLLSize = iend - anchor;
|
||||
memcpy(seqStorePtr->lit, anchor, lastLLSize);
|
||||
seqStorePtr->lit += lastLLSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
const U32 mls = ctx->appliedParams.cParams.searchLength;
|
||||
switch(mls)
|
||||
{
|
||||
default: /* includes case 3 */
|
||||
case 4 :
|
||||
ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
|
||||
case 5 :
|
||||
ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
|
||||
case 6 :
|
||||
ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
|
||||
case 7 :
|
||||
ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize,
|
||||
const U32 mls)
|
||||
{
|
||||
U32* const hashLong = ctx->hashTable;
|
||||
U32 const hBitsL = ctx->appliedParams.cParams.hashLog;
|
||||
U32* const hashSmall = ctx->chainTable;
|
||||
U32 const hBitsS = ctx->appliedParams.cParams.chainLog;
|
||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
||||
const BYTE* const base = ctx->base;
|
||||
const BYTE* const dictBase = ctx->dictBase;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 lowestIndex = ctx->lowLimit;
|
||||
const BYTE* const dictStart = dictBase + lowestIndex;
|
||||
const U32 dictLimit = ctx->dictLimit;
|
||||
const BYTE* const lowPrefixPtr = base + dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
|
||||
|
||||
/* Search Loop */
|
||||
while (ip < ilimit) { /* < instead of <=, because (ip+1) */
|
||||
const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
|
||||
const U32 matchIndex = hashSmall[hSmall];
|
||||
const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* match = matchBase + matchIndex;
|
||||
|
||||
const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
|
||||
const U32 matchLongIndex = hashLong[hLong];
|
||||
const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* matchLong = matchLongBase + matchLongIndex;
|
||||
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
|
||||
const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* repMatch = repBase + repIndex;
|
||||
size_t mLength;
|
||||
hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
|
||||
|
||||
if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
|
||||
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
||||
const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
|
||||
ip++;
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||
} else {
|
||||
if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
|
||||
const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
|
||||
const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
|
||||
U32 offset;
|
||||
mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
|
||||
offset = current - matchLongIndex;
|
||||
while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
|
||||
} else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
|
||||
size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
|
||||
U32 const matchIndex3 = hashLong[h3];
|
||||
const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
|
||||
const BYTE* match3 = match3Base + matchIndex3;
|
||||
U32 offset;
|
||||
hashLong[h3] = current + 1;
|
||||
if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
|
||||
const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
|
||||
const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
|
||||
mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
|
||||
ip++;
|
||||
offset = current+1 - matchIndex3;
|
||||
while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
|
||||
} else {
|
||||
const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
|
||||
const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
|
||||
mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
|
||||
offset = current - matchIndex;
|
||||
while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
}
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
|
||||
} else {
|
||||
ip += ((ip-anchor) >> g_searchStrength) + 1;
|
||||
continue;
|
||||
} }
|
||||
|
||||
/* found a match : store it */
|
||||
ip += mLength;
|
||||
anchor = ip;
|
||||
|
||||
if (ip <= ilimit) {
|
||||
/* Fill Table */
|
||||
hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
|
||||
hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
|
||||
hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
|
||||
hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
|
||||
/* check immediate repcode */
|
||||
while (ip <= ilimit) {
|
||||
U32 const current2 = (U32)(ip-base);
|
||||
U32 const repIndex2 = current2 - offset_2;
|
||||
const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
|
||||
if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
|
||||
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
||||
const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
|
||||
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
|
||||
U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
|
||||
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
|
||||
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
|
||||
ip += repLength2;
|
||||
anchor = ip;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} } }
|
||||
|
||||
/* save reps for next block */
|
||||
seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
|
||||
|
||||
/* Last Literals */
|
||||
{ size_t const lastLLSize = iend - anchor;
|
||||
memcpy(seqStorePtr->lit, anchor, lastLLSize);
|
||||
seqStorePtr->lit += lastLLSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
U32 const mls = ctx->appliedParams.cParams.searchLength;
|
||||
switch(mls)
|
||||
{
|
||||
default: /* includes case 3 */
|
||||
case 4 :
|
||||
ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
|
||||
case 5 :
|
||||
ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
|
||||
case 6 :
|
||||
ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
|
||||
case 7 :
|
||||
ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Binary Tree search
|
||||
***************************************/
|
||||
/** ZSTD_insertBt1() : add one or multiple positions to tree.
|
||||
* ip : assumed <= iend-8 .
|
||||
* @return : nb of positions added */
|
||||
static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
|
||||
U32 extDict)
|
||||
{
|
||||
U32* const hashTable = zc->hashTable;
|
||||
U32 const hashLog = zc->appliedParams.cParams.hashLog;
|
||||
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
|
||||
U32* const bt = zc->chainTable;
|
||||
U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
|
||||
U32 const btMask = (1 << btLog) - 1;
|
||||
U32 matchIndex = hashTable[h];
|
||||
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
||||
const BYTE* const base = zc->base;
|
||||
const BYTE* const dictBase = zc->dictBase;
|
||||
const U32 dictLimit = zc->dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const prefixStart = base + dictLimit;
|
||||
const BYTE* match;
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 btLow = btMask >= current ? 0 : current - btMask;
|
||||
U32* smallerPtr = bt + 2*(current&btMask);
|
||||
U32* largerPtr = smallerPtr + 1;
|
||||
U32 dummy32; /* to be nullified at the end */
|
||||
U32 const windowLow = zc->lowLimit;
|
||||
U32 matchEndIdx = current+8;
|
||||
size_t bestLength = 8;
|
||||
#ifdef ZSTD_C_PREDICT
|
||||
U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
|
||||
U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
|
||||
predictedSmall += (predictedSmall>0);
|
||||
predictedLarge += (predictedLarge>0);
|
||||
#endif /* ZSTD_C_PREDICT */
|
||||
|
||||
hashTable[h] = current; /* Update Hash Table */
|
||||
|
||||
while (nbCompares-- && (matchIndex > windowLow)) {
|
||||
U32* const nextPtr = bt + 2*(matchIndex & btMask);
|
||||
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||
|
||||
#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
|
||||
const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
|
||||
if (matchIndex == predictedSmall) {
|
||||
/* no need to check length, result known */
|
||||
*smallerPtr = matchIndex;
|
||||
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||
smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
|
||||
matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
|
||||
predictedSmall = predictPtr[1] + (predictPtr[1]>0);
|
||||
continue;
|
||||
}
|
||||
if (matchIndex == predictedLarge) {
|
||||
*largerPtr = matchIndex;
|
||||
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||
largerPtr = nextPtr;
|
||||
matchIndex = nextPtr[0];
|
||||
predictedLarge = predictPtr[0] + (predictPtr[0]>0);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
|
||||
match = base + matchIndex;
|
||||
if (match[matchLength] == ip[matchLength])
|
||||
matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
|
||||
} else {
|
||||
match = dictBase + matchIndex;
|
||||
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
|
||||
if (matchIndex+matchLength >= dictLimit)
|
||||
match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
|
||||
}
|
||||
|
||||
if (matchLength > bestLength) {
|
||||
bestLength = matchLength;
|
||||
if (matchLength > matchEndIdx - matchIndex)
|
||||
matchEndIdx = matchIndex + (U32)matchLength;
|
||||
}
|
||||
|
||||
if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
|
||||
break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
|
||||
|
||||
if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
|
||||
/* match is smaller than current */
|
||||
*smallerPtr = matchIndex; /* update smaller idx */
|
||||
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
|
||||
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||
smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
|
||||
matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
|
||||
} else {
|
||||
/* match is larger than current */
|
||||
*largerPtr = matchIndex;
|
||||
commonLengthLarger = matchLength;
|
||||
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||
largerPtr = nextPtr;
|
||||
matchIndex = nextPtr[0];
|
||||
} }
|
||||
|
||||
*smallerPtr = *largerPtr = 0;
|
||||
if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
|
||||
if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_insertBtAndFindBestMatch (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* const ip, const BYTE* const iend,
|
||||
size_t* offsetPtr,
|
||||
U32 nbCompares, const U32 mls,
|
||||
U32 extDict)
|
||||
{
|
||||
U32* const hashTable = zc->hashTable;
|
||||
U32 const hashLog = zc->appliedParams.cParams.hashLog;
|
||||
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
|
||||
U32* const bt = zc->chainTable;
|
||||
U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
|
||||
U32 const btMask = (1 << btLog) - 1;
|
||||
U32 matchIndex = hashTable[h];
|
||||
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
||||
const BYTE* const base = zc->base;
|
||||
const BYTE* const dictBase = zc->dictBase;
|
||||
const U32 dictLimit = zc->dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const prefixStart = base + dictLimit;
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 btLow = btMask >= current ? 0 : current - btMask;
|
||||
const U32 windowLow = zc->lowLimit;
|
||||
U32* smallerPtr = bt + 2*(current&btMask);
|
||||
U32* largerPtr = bt + 2*(current&btMask) + 1;
|
||||
U32 matchEndIdx = current+8;
|
||||
U32 dummy32; /* to be nullified at the end */
|
||||
size_t bestLength = 0;
|
||||
|
||||
hashTable[h] = current; /* Update Hash Table */
|
||||
|
||||
while (nbCompares-- && (matchIndex > windowLow)) {
|
||||
U32* const nextPtr = bt + 2*(matchIndex & btMask);
|
||||
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||
const BYTE* match;
|
||||
|
||||
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
|
||||
match = base + matchIndex;
|
||||
if (match[matchLength] == ip[matchLength])
|
||||
matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
|
||||
} else {
|
||||
match = dictBase + matchIndex;
|
||||
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
|
||||
if (matchIndex+matchLength >= dictLimit)
|
||||
match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
|
||||
}
|
||||
|
||||
if (matchLength > bestLength) {
|
||||
if (matchLength > matchEndIdx - matchIndex)
|
||||
matchEndIdx = matchIndex + (U32)matchLength;
|
||||
if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
|
||||
bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
|
||||
if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
|
||||
break; /* drop, to guarantee consistency (miss a little bit of compression) */
|
||||
}
|
||||
|
||||
if (match[matchLength] < ip[matchLength]) {
|
||||
/* match is smaller than current */
|
||||
*smallerPtr = matchIndex; /* update smaller idx */
|
||||
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
|
||||
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||
smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
|
||||
matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
|
||||
} else {
|
||||
/* match is larger than current */
|
||||
*largerPtr = matchIndex;
|
||||
commonLengthLarger = matchLength;
|
||||
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||
largerPtr = nextPtr;
|
||||
matchIndex = nextPtr[0];
|
||||
} }
|
||||
|
||||
*smallerPtr = *largerPtr = 0;
|
||||
|
||||
zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
|
||||
return bestLength;
|
||||
}
|
||||
|
||||
|
||||
static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
|
||||
{
|
||||
const BYTE* const base = zc->base;
|
||||
const U32 target = (U32)(ip - base);
|
||||
U32 idx = zc->nextToUpdate;
|
||||
|
||||
while(idx < target)
|
||||
idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
|
||||
}
|
||||
|
||||
/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
|
||||
static size_t ZSTD_BtFindBestMatch (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 maxNbAttempts, const U32 mls)
|
||||
{
|
||||
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
|
||||
ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
|
||||
return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_BtFindBestMatch_selectMLS (
|
||||
ZSTD_CCtx* zc, /* Index table will be updated */
|
||||
const BYTE* ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 maxNbAttempts, const U32 matchLengthSearch)
|
||||
{
|
||||
switch(matchLengthSearch)
|
||||
{
|
||||
default : /* includes case 3 */
|
||||
case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
|
||||
case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
|
||||
{
|
||||
const BYTE* const base = zc->base;
|
||||
const U32 target = (U32)(ip - base);
|
||||
U32 idx = zc->nextToUpdate;
|
||||
|
||||
while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
|
||||
}
|
||||
|
||||
|
||||
/** Tree updater, providing best match */
|
||||
static size_t ZSTD_BtFindBestMatch_extDict (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 maxNbAttempts, const U32 mls)
|
||||
{
|
||||
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
|
||||
ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
|
||||
return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
|
||||
ZSTD_CCtx* zc, /* Index table will be updated */
|
||||
const BYTE* ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 maxNbAttempts, const U32 matchLengthSearch)
|
||||
{
|
||||
switch(matchLengthSearch)
|
||||
{
|
||||
default : /* includes case 3 */
|
||||
case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
|
||||
case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* *********************************
|
||||
* Hash Chain
|
||||
***********************************/
|
||||
#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
|
||||
|
||||
/* Update chains up to ip (excluded)
|
||||
Assumption : always within prefix (i.e. not within extDict) */
|
||||
FORCE_INLINE_TEMPLATE
|
||||
U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
|
||||
{
|
||||
U32* const hashTable = zc->hashTable;
|
||||
const U32 hashLog = zc->appliedParams.cParams.hashLog;
|
||||
U32* const chainTable = zc->chainTable;
|
||||
const U32 chainMask = (1 << zc->appliedParams.cParams.chainLog) - 1;
|
||||
const BYTE* const base = zc->base;
|
||||
const U32 target = (U32)(ip - base);
|
||||
U32 idx = zc->nextToUpdate;
|
||||
|
||||
while(idx < target) { /* catch up */
|
||||
size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
|
||||
NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
|
||||
hashTable[h] = idx;
|
||||
idx++;
|
||||
}
|
||||
|
||||
zc->nextToUpdate = target;
|
||||
return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
|
||||
}
|
||||
|
||||
|
||||
/* inlining is important to hardwire a hot branch (template emulation) */
|
||||
FORCE_INLINE_TEMPLATE
|
||||
size_t ZSTD_HcFindBestMatch_generic (
|
||||
ZSTD_CCtx* zc, /* Index table will be updated */
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 maxNbAttempts, const U32 mls, const U32 extDict)
|
||||
{
|
||||
U32* const chainTable = zc->chainTable;
|
||||
const U32 chainSize = (1 << zc->appliedParams.cParams.chainLog);
|
||||
const U32 chainMask = chainSize-1;
|
||||
const BYTE* const base = zc->base;
|
||||
const BYTE* const dictBase = zc->dictBase;
|
||||
const U32 dictLimit = zc->dictLimit;
|
||||
const BYTE* const prefixStart = base + dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const U32 lowLimit = zc->lowLimit;
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 minChain = current > chainSize ? current - chainSize : 0;
|
||||
int nbAttempts=maxNbAttempts;
|
||||
size_t ml=4-1;
|
||||
|
||||
/* HC4 match finder */
|
||||
U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
|
||||
|
||||
for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
|
||||
const BYTE* match;
|
||||
size_t currentMl=0;
|
||||
if ((!extDict) || matchIndex >= dictLimit) {
|
||||
match = base + matchIndex;
|
||||
if (match[ml] == ip[ml]) /* potentially better */
|
||||
currentMl = ZSTD_count(ip, match, iLimit);
|
||||
} else {
|
||||
match = dictBase + matchIndex;
|
||||
if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
|
||||
currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
|
||||
}
|
||||
|
||||
/* save best solution */
|
||||
if (currentMl > ml) {
|
||||
ml = currentMl;
|
||||
*offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
|
||||
if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
|
||||
}
|
||||
|
||||
if (matchIndex <= minChain) break;
|
||||
matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
|
||||
}
|
||||
|
||||
return ml;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 maxNbAttempts, const U32 matchLengthSearch)
|
||||
{
|
||||
switch(matchLengthSearch)
|
||||
{
|
||||
default : /* includes case 3 */
|
||||
case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
|
||||
case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 maxNbAttempts, const U32 matchLengthSearch)
|
||||
{
|
||||
switch(matchLengthSearch)
|
||||
{
|
||||
default : /* includes case 3 */
|
||||
case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
|
||||
case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* *******************************
|
||||
* Common parser - lazy strategy
|
||||
*********************************/
|
||||
FORCE_INLINE_TEMPLATE
|
||||
void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize,
|
||||
const U32 searchMethod, const U32 depth)
|
||||
{
|
||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
const BYTE* const base = ctx->base + ctx->dictLimit;
|
||||
|
||||
U32 const maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
|
||||
U32 const mls = ctx->appliedParams.cParams.searchLength;
|
||||
|
||||
typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
|
||||
size_t* offsetPtr,
|
||||
U32 maxNbAttempts, U32 matchLengthSearch);
|
||||
searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
|
||||
U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1], savedOffset=0;
|
||||
|
||||
/* init */
|
||||
ip += (ip==base);
|
||||
ctx->nextToUpdate3 = ctx->nextToUpdate;
|
||||
{ U32 const maxRep = (U32)(ip-base);
|
||||
if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
|
||||
if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
|
||||
}
|
||||
|
||||
/* Match Loop */
|
||||
while (ip < ilimit) {
|
||||
size_t matchLength=0;
|
||||
size_t offset=0;
|
||||
const BYTE* start=ip+1;
|
||||
|
||||
/* check repCode */
|
||||
if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
|
||||
/* repcode : we take it */
|
||||
matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
|
||||
if (depth==0) goto _storeSequence;
|
||||
}
|
||||
|
||||
/* first search (depth 0) */
|
||||
{ size_t offsetFound = 99999999;
|
||||
size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
|
||||
if (ml2 > matchLength)
|
||||
matchLength = ml2, start = ip, offset=offsetFound;
|
||||
}
|
||||
|
||||
if (matchLength < 4) {
|
||||
ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* let's try to find a better solution */
|
||||
if (depth>=1)
|
||||
while (ip<ilimit) {
|
||||
ip ++;
|
||||
if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
|
||||
size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
|
||||
int const gain2 = (int)(mlRep * 3);
|
||||
int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
|
||||
if ((mlRep >= 4) && (gain2 > gain1))
|
||||
matchLength = mlRep, offset = 0, start = ip;
|
||||
}
|
||||
{ size_t offset2=99999999;
|
||||
size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
|
||||
int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
|
||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
|
||||
if ((ml2 >= 4) && (gain2 > gain1)) {
|
||||
matchLength = ml2, offset = offset2, start = ip;
|
||||
continue; /* search a better one */
|
||||
} }
|
||||
|
||||
/* let's find an even better one */
|
||||
if ((depth==2) && (ip<ilimit)) {
|
||||
ip ++;
|
||||
if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
|
||||
size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
|
||||
int const gain2 = (int)(ml2 * 4);
|
||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
|
||||
if ((ml2 >= 4) && (gain2 > gain1))
|
||||
matchLength = ml2, offset = 0, start = ip;
|
||||
}
|
||||
{ size_t offset2=99999999;
|
||||
size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
|
||||
int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
|
||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
|
||||
if ((ml2 >= 4) && (gain2 > gain1)) {
|
||||
matchLength = ml2, offset = offset2, start = ip;
|
||||
continue;
|
||||
} } }
|
||||
break; /* nothing found : store previous solution */
|
||||
}
|
||||
|
||||
/* NOTE:
|
||||
* start[-offset+ZSTD_REP_MOVE-1] is undefined behavior.
|
||||
* (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which
|
||||
* overflows the pointer, which is undefined behavior.
|
||||
*/
|
||||
/* catch up */
|
||||
if (offset) {
|
||||
while ( (start > anchor)
|
||||
&& (start > base+offset-ZSTD_REP_MOVE)
|
||||
&& (start[-1] == (start-offset+ZSTD_REP_MOVE)[-1]) ) /* only search for offset within prefix */
|
||||
{ start--; matchLength++; }
|
||||
offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
|
||||
}
|
||||
/* store sequence */
|
||||
_storeSequence:
|
||||
{ size_t const litLength = start - anchor;
|
||||
ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
|
||||
anchor = ip = start + matchLength;
|
||||
}
|
||||
|
||||
/* check immediate repcode */
|
||||
while ( (ip <= ilimit)
|
||||
&& ((offset_2>0)
|
||||
& (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
|
||||
/* store sequence */
|
||||
matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
||||
offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
|
||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
|
||||
ip += matchLength;
|
||||
anchor = ip;
|
||||
continue; /* faster when present ... (?) */
|
||||
} }
|
||||
|
||||
/* Save reps for next block */
|
||||
seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
|
||||
seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
|
||||
|
||||
/* Last Literals */
|
||||
{ size_t const lastLLSize = iend - anchor;
|
||||
memcpy(seqStorePtr->lit, anchor, lastLLSize);
|
||||
seqStorePtr->lit += lastLLSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
|
||||
}
|
||||
|
||||
static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
|
||||
}
|
||||
|
||||
static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
|
||||
}
|
||||
|
||||
static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize,
|
||||
const U32 searchMethod, const U32 depth)
|
||||
{
|
||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
const BYTE* const base = ctx->base;
|
||||
const U32 dictLimit = ctx->dictLimit;
|
||||
const U32 lowestIndex = ctx->lowLimit;
|
||||
const BYTE* const prefixStart = base + dictLimit;
|
||||
const BYTE* const dictBase = ctx->dictBase;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const dictStart = dictBase + ctx->lowLimit;
|
||||
|
||||
const U32 maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
|
||||
const U32 mls = ctx->appliedParams.cParams.searchLength;
|
||||
|
||||
typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
|
||||
size_t* offsetPtr,
|
||||
U32 maxNbAttempts, U32 matchLengthSearch);
|
||||
searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
|
||||
|
||||
U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1];
|
||||
|
||||
/* init */
|
||||
ctx->nextToUpdate3 = ctx->nextToUpdate;
|
||||
ip += (ip == prefixStart);
|
||||
|
||||
/* Match Loop */
|
||||
while (ip < ilimit) {
|
||||
size_t matchLength=0;
|
||||
size_t offset=0;
|
||||
const BYTE* start=ip+1;
|
||||
U32 current = (U32)(ip-base);
|
||||
|
||||
/* check repCode */
|
||||
{ const U32 repIndex = (U32)(current+1 - offset_1);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
|
||||
if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
|
||||
/* repcode detected we should take it */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
|
||||
if (depth==0) goto _storeSequence;
|
||||
} }
|
||||
|
||||
/* first search (depth 0) */
|
||||
{ size_t offsetFound = 99999999;
|
||||
size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
|
||||
if (ml2 > matchLength)
|
||||
matchLength = ml2, start = ip, offset=offsetFound;
|
||||
}
|
||||
|
||||
if (matchLength < 4) {
|
||||
ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* let's try to find a better solution */
|
||||
if (depth>=1)
|
||||
while (ip<ilimit) {
|
||||
ip ++;
|
||||
current++;
|
||||
/* check repCode */
|
||||
if (offset) {
|
||||
const U32 repIndex = (U32)(current - offset_1);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
|
||||
if (MEM_read32(ip) == MEM_read32(repMatch)) {
|
||||
/* repcode detected */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
|
||||
int const gain2 = (int)(repLength * 3);
|
||||
int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
|
||||
if ((repLength >= 4) && (gain2 > gain1))
|
||||
matchLength = repLength, offset = 0, start = ip;
|
||||
} }
|
||||
|
||||
/* search match, depth 1 */
|
||||
{ size_t offset2=99999999;
|
||||
size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
|
||||
int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
|
||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
|
||||
if ((ml2 >= 4) && (gain2 > gain1)) {
|
||||
matchLength = ml2, offset = offset2, start = ip;
|
||||
continue; /* search a better one */
|
||||
} }
|
||||
|
||||
/* let's find an even better one */
|
||||
if ((depth==2) && (ip<ilimit)) {
|
||||
ip ++;
|
||||
current++;
|
||||
/* check repCode */
|
||||
if (offset) {
|
||||
const U32 repIndex = (U32)(current - offset_1);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
|
||||
if (MEM_read32(ip) == MEM_read32(repMatch)) {
|
||||
/* repcode detected */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
|
||||
int const gain2 = (int)(repLength * 4);
|
||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
|
||||
if ((repLength >= 4) && (gain2 > gain1))
|
||||
matchLength = repLength, offset = 0, start = ip;
|
||||
} }
|
||||
|
||||
/* search match, depth 2 */
|
||||
{ size_t offset2=99999999;
|
||||
size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
|
||||
int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
|
||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
|
||||
if ((ml2 >= 4) && (gain2 > gain1)) {
|
||||
matchLength = ml2, offset = offset2, start = ip;
|
||||
continue;
|
||||
} } }
|
||||
break; /* nothing found : store previous solution */
|
||||
}
|
||||
|
||||
/* catch up */
|
||||
if (offset) {
|
||||
U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
|
||||
const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
|
||||
const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
|
||||
while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
|
||||
offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
|
||||
}
|
||||
|
||||
/* store sequence */
|
||||
_storeSequence:
|
||||
{ size_t const litLength = start - anchor;
|
||||
ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
|
||||
anchor = ip = start + matchLength;
|
||||
}
|
||||
|
||||
/* check immediate repcode */
|
||||
while (ip <= ilimit) {
|
||||
const U32 repIndex = (U32)((ip-base) - offset_2);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
|
||||
if (MEM_read32(ip) == MEM_read32(repMatch)) {
|
||||
/* repcode detected we should take it */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
|
||||
offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
|
||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
|
||||
ip += matchLength;
|
||||
anchor = ip;
|
||||
continue; /* faster when present ... (?) */
|
||||
}
|
||||
break;
|
||||
} }
|
||||
|
||||
/* Save reps for next block */
|
||||
seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
|
||||
|
||||
/* Last Literals */
|
||||
{ size_t const lastLLSize = iend - anchor;
|
||||
memcpy(seqStorePtr->lit, anchor, lastLLSize);
|
||||
seqStorePtr->lit += lastLLSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
|
||||
}
|
||||
|
||||
static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
|
||||
}
|
||||
|
||||
static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
|
||||
}
|
||||
|
||||
static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
|
||||
}
|
||||
|
||||
|
||||
/* The optimal parser */
|
||||
#include "zstd_opt.h"
|
||||
|
||||
static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
#ifdef ZSTD_OPT_H_91842398743
|
||||
ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
|
||||
#else
|
||||
(void)ctx; (void)src; (void)srcSize;
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
#ifdef ZSTD_OPT_H_91842398743
|
||||
ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
|
||||
#else
|
||||
(void)ctx; (void)src; (void)srcSize;
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
#ifdef ZSTD_OPT_H_91842398743
|
||||
ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
|
||||
#else
|
||||
(void)ctx; (void)src; (void)srcSize;
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
#ifdef ZSTD_OPT_H_91842398743
|
||||
ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
|
||||
#else
|
||||
(void)ctx; (void)src; (void)srcSize;
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* ZSTD_selectBlockCompressor() :
|
||||
* Not static, but internal use only (used by long distance matcher)
|
||||
* assumption : strat is a valid strategy */
|
||||
typedef size_t (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
|
||||
typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
|
||||
{
|
||||
static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = {
|
||||
{ ZSTD_compressBlock_fast /* default for 0 */,
|
||||
@@ -1534,37 +2819,18 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict
|
||||
return blockCompressor[extDict!=0][(U32)strat];
|
||||
}
|
||||
|
||||
static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
|
||||
const BYTE* anchor, size_t lastLLSize)
|
||||
{
|
||||
memcpy(seqStorePtr->lit, anchor, lastLLSize);
|
||||
seqStorePtr->lit += lastLLSize;
|
||||
}
|
||||
|
||||
static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
||||
{
|
||||
ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, zc->lowLimit < zc->dictLimit);
|
||||
const BYTE* const base = zc->base;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const U32 current = (U32)(istart-base);
|
||||
size_t lastLLSize;
|
||||
const BYTE* anchor;
|
||||
U32 const extDict = zc->lowLimit < zc->dictLimit;
|
||||
const ZSTD_blockCompressor blockCompressor =
|
||||
zc->appliedParams.ldmParams.enableLdm
|
||||
? (extDict ? ZSTD_compressBlock_ldm_extDict : ZSTD_compressBlock_ldm)
|
||||
: ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict);
|
||||
|
||||
if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */
|
||||
ZSTD_resetSeqStore(&(zc->seqStore));
|
||||
if (current > zc->nextToUpdate + 384)
|
||||
zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384)); /* limited update after finding a very long match */
|
||||
|
||||
lastLLSize = blockCompressor(zc, src, srcSize);
|
||||
|
||||
/* Last literals */
|
||||
anchor = (const BYTE*)src + srcSize - lastLLSize;
|
||||
ZSTD_storeLastLiterals(&zc->seqStore, anchor, lastLLSize);
|
||||
|
||||
blockCompressor(zc, src, srcSize);
|
||||
return ZSTD_compressSequences(&zc->seqStore, zc->entropy, &zc->appliedParams.cParams, dst, dstCapacity, srcSize);
|
||||
}
|
||||
|
||||
@@ -1649,7 +2915,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
|
||||
|
||||
|
||||
static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
|
||||
ZSTD_CCtx_params params, U64 pledgedSrcSize, U32 dictID)
|
||||
ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
|
||||
{ BYTE* const op = (BYTE*)dst;
|
||||
U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
|
||||
U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
|
||||
@@ -1703,7 +2969,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
|
||||
|
||||
if (frame && (cctx->stage==ZSTDcs_init)) {
|
||||
fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams,
|
||||
cctx->pledgedSrcSizePlusOne-1, cctx->dictID);
|
||||
cctx->pledgedSrcSizePlusOne-1, cctx->dictID);
|
||||
if (ZSTD_isError(fhSize)) return fhSize;
|
||||
dstCapacity -= fhSize;
|
||||
dst = (char*)dst + fhSize;
|
||||
@@ -1752,8 +3018,10 @@ size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
|
||||
|
||||
size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
|
||||
{
|
||||
ZSTD_compressionParameters const cParams =
|
||||
ZSTD_getCParamsFromCCtxParams(cctx->appliedParams, 0, 0);
|
||||
U32 const cLevel = cctx->compressionLevel;
|
||||
ZSTD_compressionParameters cParams = (cLevel == ZSTD_CLEVEL_CUSTOM) ?
|
||||
cctx->appliedParams.cParams :
|
||||
ZSTD_getCParams(cLevel, 0, 0);
|
||||
return MIN (ZSTD_BLOCKSIZE_MAX, 1 << cParams.windowLog);
|
||||
}
|
||||
|
||||
@@ -1778,7 +3046,7 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t
|
||||
zc->dictBase = zc->base;
|
||||
zc->base += ip - zc->nextSrc;
|
||||
zc->nextToUpdate = zc->dictLimit;
|
||||
zc->loadedDictEnd = zc->appliedParams.forceWindow ? 0 : (U32)(iend - zc->base);
|
||||
zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
|
||||
|
||||
zc->nextSrc = iend;
|
||||
if (srcSize <= HASH_READ_SIZE) return 0;
|
||||
@@ -1788,6 +3056,7 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t
|
||||
case ZSTD_fast:
|
||||
ZSTD_fillHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
|
||||
break;
|
||||
|
||||
case ZSTD_dfast:
|
||||
ZSTD_fillDoubleHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
|
||||
break;
|
||||
@@ -1952,7 +3221,7 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictMode_e dictMode,
|
||||
const ZSTD_CDict* cdict,
|
||||
ZSTD_CCtx_params params, U64 pledgedSrcSize,
|
||||
ZSTD_parameters params, U64 pledgedSrcSize,
|
||||
ZSTD_buffered_policy_e zbuff)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTD_compressBegin_internal");
|
||||
@@ -1973,19 +3242,6 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
|
||||
return ZSTD_compress_insertDictionary(cctx, dict, dictSize, dictMode);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBegin_advanced_internal(
|
||||
ZSTD_CCtx* cctx,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictMode_e dictMode,
|
||||
ZSTD_CCtx_params params,
|
||||
unsigned long long pledgedSrcSize)
|
||||
{
|
||||
/* compression parameters verification and optimization */
|
||||
CHECK_F( ZSTD_checkCParams(params.cParams) );
|
||||
return ZSTD_compressBegin_internal(cctx, dict, dictSize, dictMode, NULL,
|
||||
params, pledgedSrcSize,
|
||||
ZSTDb_not_buffered);
|
||||
}
|
||||
|
||||
/*! ZSTD_compressBegin_advanced() :
|
||||
* @return : 0, or an error code */
|
||||
@@ -1993,22 +3249,21 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_parameters params, unsigned long long pledgedSrcSize)
|
||||
{
|
||||
ZSTD_CCtx_params const cctxParams =
|
||||
ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
|
||||
return ZSTD_compressBegin_advanced_internal(cctx, dict, dictSize, ZSTD_dm_auto,
|
||||
cctxParams,
|
||||
pledgedSrcSize);
|
||||
/* compression parameters verification and optimization */
|
||||
CHECK_F(ZSTD_checkCParams(params.cParams));
|
||||
return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
|
||||
params, pledgedSrcSize, ZSTDb_not_buffered);
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
|
||||
{
|
||||
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
|
||||
ZSTD_CCtx_params const cctxParams =
|
||||
ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
|
||||
return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
|
||||
cctxParams, 0, ZSTDb_not_buffered);
|
||||
params, 0, ZSTDb_not_buffered);
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
|
||||
{
|
||||
return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
|
||||
@@ -2085,13 +3340,9 @@ static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
|
||||
const void* dict,size_t dictSize,
|
||||
ZSTD_parameters params)
|
||||
{
|
||||
ZSTD_CCtx_params const cctxParams =
|
||||
ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
|
||||
return ZSTD_compress_advanced_internal(cctx,
|
||||
dst, dstCapacity,
|
||||
src, srcSize,
|
||||
dict, dictSize,
|
||||
cctxParams);
|
||||
CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
|
||||
params, srcSize, ZSTDb_not_buffered) );
|
||||
return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
|
||||
}
|
||||
|
||||
size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
|
||||
@@ -2104,19 +3355,6 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
|
||||
return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
|
||||
}
|
||||
|
||||
/* Internal */
|
||||
size_t ZSTD_compress_advanced_internal(
|
||||
ZSTD_CCtx* cctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
const void* dict,size_t dictSize,
|
||||
ZSTD_CCtx_params params)
|
||||
{
|
||||
CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
|
||||
params, srcSize, ZSTDb_not_buffered) );
|
||||
return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
|
||||
}
|
||||
|
||||
size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize,
|
||||
const void* dict, size_t dictSize, int compressionLevel)
|
||||
{
|
||||
@@ -2146,21 +3384,18 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcS
|
||||
|
||||
/*! ZSTD_estimateCDictSize_advanced() :
|
||||
* Estimate amount of memory that will be needed to create a dictionary with following arguments */
|
||||
size_t ZSTD_estimateCDictSize_advanced(
|
||||
size_t dictSize, ZSTD_compressionParameters cParams,
|
||||
ZSTD_dictLoadMethod_e dictLoadMethod)
|
||||
size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference)
|
||||
{
|
||||
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)
|
||||
+ (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
|
||||
DEBUGLOG(5, "CCtx estimate : %u", (U32)ZSTD_estimateCCtxSize_advanced(cParams));
|
||||
return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced(cParams)
|
||||
+ (byReference ? 0 : dictSize);
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
|
||||
{
|
||||
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
|
||||
return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
|
||||
return ZSTD_estimateCDictSize_advanced(dictSize, cParams, 0);
|
||||
}
|
||||
|
||||
size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
|
||||
@@ -2171,15 +3406,22 @@ size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
|
||||
return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
|
||||
}
|
||||
|
||||
static ZSTD_parameters ZSTD_makeParams(ZSTD_compressionParameters cParams, ZSTD_frameParameters fParams)
|
||||
{
|
||||
ZSTD_parameters params;
|
||||
params.cParams = cParams;
|
||||
params.fParams = fParams;
|
||||
return params;
|
||||
}
|
||||
|
||||
static size_t ZSTD_initCDict_internal(
|
||||
ZSTD_CDict* cdict,
|
||||
const void* dictBuffer, size_t dictSize,
|
||||
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||
ZSTD_dictMode_e dictMode,
|
||||
unsigned byReference, ZSTD_dictMode_e dictMode,
|
||||
ZSTD_compressionParameters cParams)
|
||||
{
|
||||
DEBUGLOG(5, "ZSTD_initCDict_internal, mode %u", (U32)dictMode);
|
||||
if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
|
||||
if ((byReference) || (!dictBuffer) || (!dictSize)) {
|
||||
cdict->dictBuffer = NULL;
|
||||
cdict->dictContent = dictBuffer;
|
||||
} else {
|
||||
@@ -2191,12 +3433,13 @@ static size_t ZSTD_initCDict_internal(
|
||||
}
|
||||
cdict->dictContentSize = dictSize;
|
||||
|
||||
{ ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams;
|
||||
cctxParams.cParams = cParams;
|
||||
{ ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */,
|
||||
0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */
|
||||
ZSTD_parameters const params = ZSTD_makeParams(cParams, fParams);
|
||||
CHECK_F( ZSTD_compressBegin_internal(cdict->refContext,
|
||||
cdict->dictContent, dictSize, dictMode,
|
||||
NULL,
|
||||
cctxParams, ZSTD_CONTENTSIZE_UNKNOWN,
|
||||
params, ZSTD_CONTENTSIZE_UNKNOWN,
|
||||
ZSTDb_not_buffered) );
|
||||
}
|
||||
|
||||
@@ -2204,8 +3447,7 @@ static size_t ZSTD_initCDict_internal(
|
||||
}
|
||||
|
||||
ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
|
||||
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||
ZSTD_dictMode_e dictMode,
|
||||
unsigned byReference, ZSTD_dictMode_e dictMode,
|
||||
ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
|
||||
{
|
||||
DEBUGLOG(5, "ZSTD_createCDict_advanced, mode %u", (U32)dictMode);
|
||||
@@ -2220,9 +3462,10 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
|
||||
return NULL;
|
||||
}
|
||||
cdict->refContext = cctx;
|
||||
|
||||
if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
|
||||
dictBuffer, dictSize,
|
||||
dictLoadMethod, dictMode,
|
||||
byReference, dictMode,
|
||||
cParams) )) {
|
||||
ZSTD_freeCDict(cdict);
|
||||
return NULL;
|
||||
@@ -2236,7 +3479,7 @@ ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionL
|
||||
{
|
||||
ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
|
||||
return ZSTD_createCDict_advanced(dict, dictSize,
|
||||
ZSTD_dlm_byCopy, ZSTD_dm_auto,
|
||||
0 /* byReference */, ZSTD_dm_auto,
|
||||
cParams, ZSTD_defaultCMem);
|
||||
}
|
||||
|
||||
@@ -2244,7 +3487,7 @@ ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int
|
||||
{
|
||||
ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
|
||||
return ZSTD_createCDict_advanced(dict, dictSize,
|
||||
ZSTD_dlm_byRef, ZSTD_dm_auto,
|
||||
1 /* byReference */, ZSTD_dm_auto,
|
||||
cParams, ZSTD_defaultCMem);
|
||||
}
|
||||
|
||||
@@ -2274,12 +3517,11 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
|
||||
*/
|
||||
ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||
ZSTD_dictMode_e dictMode,
|
||||
unsigned byReference, ZSTD_dictMode_e dictMode,
|
||||
ZSTD_compressionParameters cParams)
|
||||
{
|
||||
size_t const cctxSize = ZSTD_estimateCCtxSize_advanced_usingCParams(cParams);
|
||||
size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize)
|
||||
size_t const cctxSize = ZSTD_estimateCCtxSize_advanced(cParams);
|
||||
size_t const neededSize = sizeof(ZSTD_CDict) + (byReference ? 0 : dictSize)
|
||||
+ cctxSize;
|
||||
ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
|
||||
void* ptr;
|
||||
@@ -2289,7 +3531,7 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
|
||||
(U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize));
|
||||
if (workspaceSize < neededSize) return NULL;
|
||||
|
||||
if (dictLoadMethod == ZSTD_dlm_byCopy) {
|
||||
if (!byReference) {
|
||||
memcpy(cdict+1, dict, dictSize);
|
||||
dict = cdict+1;
|
||||
ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize;
|
||||
@@ -2300,15 +3542,15 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
|
||||
|
||||
if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
|
||||
dict, dictSize,
|
||||
ZSTD_dlm_byRef, dictMode,
|
||||
1 /* byReference */, dictMode,
|
||||
cParams) ))
|
||||
return NULL;
|
||||
|
||||
return cdict;
|
||||
}
|
||||
|
||||
ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) {
|
||||
return cdict->refContext->appliedParams.cParams;
|
||||
ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
|
||||
return ZSTD_getParamsFromCCtx(cdict->refContext);
|
||||
}
|
||||
|
||||
/* ZSTD_compressBegin_usingCDict_advanced() :
|
||||
@@ -2318,8 +3560,7 @@ size_t ZSTD_compressBegin_usingCDict_advanced(
|
||||
ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
|
||||
{
|
||||
if (cdict==NULL) return ERROR(dictionary_wrong);
|
||||
{ ZSTD_CCtx_params params = cctx->requestedParams;
|
||||
params.cParams = ZSTD_getCParamsFromCDict(cdict);
|
||||
{ ZSTD_parameters params = cdict->refContext->appliedParams;
|
||||
params.fParams = fParams;
|
||||
DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced");
|
||||
return ZSTD_compressBegin_internal(cctx,
|
||||
@@ -2403,7 +3644,7 @@ size_t ZSTD_CStreamOutSize(void)
|
||||
static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs,
|
||||
const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode,
|
||||
const ZSTD_CDict* cdict,
|
||||
const ZSTD_CCtx_params params, unsigned long long pledgedSrcSize)
|
||||
ZSTD_parameters params, unsigned long long pledgedSrcSize)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTD_resetCStream_internal");
|
||||
/* params are supposed to be fully validated at this point */
|
||||
@@ -2427,11 +3668,13 @@ static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs,
|
||||
|
||||
size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
|
||||
{
|
||||
ZSTD_CCtx_params params = zcs->requestedParams;
|
||||
ZSTD_parameters params = zcs->requestedParams;
|
||||
params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
|
||||
params.cParams = ZSTD_getCParamsFromCCtxParams(params, pledgedSrcSize, 0);
|
||||
DEBUGLOG(5, "ZSTD_resetCStream");
|
||||
return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, zcs->cdict, params, pledgedSrcSize);
|
||||
if (zcs->compressionLevel != ZSTD_CLEVEL_CUSTOM) {
|
||||
params.cParams = ZSTD_getCParams(zcs->compressionLevel, pledgedSrcSize, 0 /* dictSize */);
|
||||
}
|
||||
return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->dictMode, zcs->cdict, params, pledgedSrcSize);
|
||||
}
|
||||
|
||||
/*! ZSTD_initCStream_internal() :
|
||||
@@ -2440,8 +3683,9 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
|
||||
* Assumption 2 : either dict, or cdict, is defined, not both */
|
||||
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)
|
||||
ZSTD_parameters params, unsigned long long pledgedSrcSize)
|
||||
{
|
||||
DEBUGLOG(5, "ZSTD_initCStream_internal");
|
||||
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
|
||||
assert(!((dict) && (cdict))); /* either dict or cdict, not both */
|
||||
|
||||
@@ -2453,23 +3697,23 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
|
||||
}
|
||||
ZSTD_freeCDict(zcs->cdictLocal);
|
||||
zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
|
||||
ZSTD_dlm_byCopy, ZSTD_dm_auto,
|
||||
zcs->dictContentByRef, zcs->dictMode,
|
||||
params.cParams, zcs->customMem);
|
||||
zcs->cdict = zcs->cdictLocal;
|
||||
if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
|
||||
} else {
|
||||
if (cdict) {
|
||||
params.cParams = ZSTD_getCParamsFromCDict(cdict); /* cParams are enforced from cdict */
|
||||
ZSTD_parameters const cdictParams = ZSTD_getParamsFromCDict(cdict);
|
||||
params.cParams = cdictParams.cParams; /* cParams are enforced from cdict */
|
||||
}
|
||||
ZSTD_freeCDict(zcs->cdictLocal);
|
||||
zcs->cdictLocal = NULL;
|
||||
zcs->cdict = cdict;
|
||||
}
|
||||
|
||||
params.compressionLevel = ZSTD_CLEVEL_CUSTOM;
|
||||
zcs->requestedParams = params;
|
||||
|
||||
return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, zcs->cdict, params, pledgedSrcSize);
|
||||
zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM;
|
||||
return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->dictMode, zcs->cdict, params, pledgedSrcSize);
|
||||
}
|
||||
|
||||
/* ZSTD_initCStream_usingCDict_advanced() :
|
||||
@@ -2480,8 +3724,7 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
|
||||
unsigned long long pledgedSrcSize)
|
||||
{ /* cannot handle NULL cdict (does not know what to do) */
|
||||
if (!cdict) return ERROR(dictionary_wrong);
|
||||
{ ZSTD_CCtx_params params = zcs->requestedParams;
|
||||
params.cParams = ZSTD_getCParamsFromCDict(cdict);
|
||||
{ ZSTD_parameters params = ZSTD_getParamsFromCDict(cdict);
|
||||
params.fParams = fParams;
|
||||
return ZSTD_initCStream_internal(zcs,
|
||||
NULL, 0, cdict,
|
||||
@@ -2500,32 +3743,30 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_parameters params, unsigned long long pledgedSrcSize)
|
||||
{
|
||||
ZSTD_CCtx_params const cctxParams =
|
||||
ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
|
||||
CHECK_F( ZSTD_checkCParams(params.cParams) );
|
||||
return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, pledgedSrcSize);
|
||||
zcs->requestedParams = params;
|
||||
zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM;
|
||||
return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, pledgedSrcSize);
|
||||
}
|
||||
|
||||
size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
|
||||
{
|
||||
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
|
||||
ZSTD_CCtx_params const cctxParams =
|
||||
ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
|
||||
return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, 0);
|
||||
zcs->compressionLevel = compressionLevel;
|
||||
return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, 0);
|
||||
}
|
||||
|
||||
size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
|
||||
{
|
||||
ZSTD_CCtx_params cctxParams;
|
||||
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
|
||||
cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
|
||||
cctxParams.fParams.contentSizeFlag = (pledgedSrcSize>0);
|
||||
return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, cctxParams, pledgedSrcSize);
|
||||
ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
|
||||
params.fParams.contentSizeFlag = (pledgedSrcSize>0);
|
||||
return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, params, pledgedSrcSize);
|
||||
}
|
||||
|
||||
size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
|
||||
{
|
||||
return ZSTD_initCStream_srcSize(zcs, compressionLevel, 0);
|
||||
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0);
|
||||
return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, params, 0);
|
||||
}
|
||||
|
||||
/*====== Compression ======*/
|
||||
@@ -2693,6 +3934,15 @@ size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuf
|
||||
return ZSTD_compressStream_generic(zcs, output, input, ZSTD_e_continue);
|
||||
}
|
||||
|
||||
/*! ZSTDMT_initCStream_internal() :
|
||||
* Private use only. Init streaming operation.
|
||||
* expects params to be valid.
|
||||
* must receive dict, or cdict, or none, but not both.
|
||||
* @return : 0, or an error code */
|
||||
size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs,
|
||||
const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
|
||||
ZSTD_parameters params, unsigned long long pledgedSrcSize);
|
||||
|
||||
|
||||
size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
|
||||
ZSTD_outBuffer* output,
|
||||
@@ -2706,39 +3956,29 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
|
||||
|
||||
/* transparent initialization stage */
|
||||
if (cctx->streamStage == zcss_init) {
|
||||
ZSTD_prefixDict const prefixDict = cctx->prefixDict;
|
||||
ZSTD_CCtx_params params = cctx->requestedParams;
|
||||
params.cParams = ZSTD_getCParamsFromCCtxParams(
|
||||
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 */
|
||||
const void* const prefix = cctx->prefix;
|
||||
size_t const prefixSize = cctx->prefixSize;
|
||||
ZSTD_parameters params = cctx->requestedParams;
|
||||
if (cctx->compressionLevel != ZSTD_CLEVEL_CUSTOM)
|
||||
params.cParams = ZSTD_getCParams(cctx->compressionLevel,
|
||||
cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
|
||||
cctx->prefix = NULL; cctx->prefixSize = 0; /* single usage */
|
||||
assert(prefix==NULL || cctx->cdict==NULL); /* only one can be set */
|
||||
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
if (params.nbThreads > 1) {
|
||||
if (cctx->mtctx == NULL || cctx->appliedParams.nbThreads != params.nbThreads) {
|
||||
ZSTDMT_freeCCtx(cctx->mtctx);
|
||||
cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbThreads, cctx->customMem);
|
||||
if (cctx->mtctx == NULL) return ERROR(memory_allocation);
|
||||
}
|
||||
DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", params.nbThreads);
|
||||
CHECK_F( ZSTDMT_initCStream_internal(
|
||||
cctx->mtctx,
|
||||
prefixDict.dict, prefixDict.dictSize, ZSTD_dm_rawContent,
|
||||
cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) );
|
||||
if (cctx->nbThreads > 1) {
|
||||
DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", cctx->nbThreads);
|
||||
CHECK_F( ZSTDMT_initCStream_internal(cctx->mtctx, prefix, prefixSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) );
|
||||
cctx->streamStage = zcss_load;
|
||||
cctx->appliedParams.nbThreads = params.nbThreads;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
CHECK_F( ZSTD_resetCStream_internal(
|
||||
cctx, prefixDict.dict, prefixDict.dictSize,
|
||||
prefixDict.dictMode, cctx->cdict, params,
|
||||
cctx->pledgedSrcSizePlusOne-1) );
|
||||
CHECK_F( ZSTD_resetCStream_internal(cctx, prefix, prefixSize, cctx->dictMode, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) );
|
||||
} }
|
||||
|
||||
/* compression stage */
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
if (cctx->appliedParams.nbThreads > 1) {
|
||||
if (cctx->nbThreads > 1) {
|
||||
size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
|
||||
DEBUGLOG(5, "ZSTDMT_compressStream_generic : %u", (U32)flushMin);
|
||||
if ( ZSTD_isError(flushMin)
|
||||
@@ -2748,6 +3988,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
|
||||
return flushMin;
|
||||
}
|
||||
#endif
|
||||
|
||||
CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) );
|
||||
DEBUGLOG(5, "completed ZSTD_compress_generic");
|
||||
return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
|
||||
@@ -2948,7 +4189,6 @@ ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long l
|
||||
if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
|
||||
{ ZSTD_compressionParameters const cp = ZSTD_defaultCParameters[tableID][compressionLevel];
|
||||
return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); }
|
||||
|
||||
}
|
||||
|
||||
/*! ZSTD_getParams() :
|
||||
|
||||
@@ -1,307 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ZSTD_COMPRESS_H
|
||||
#define ZSTD_COMPRESS_H
|
||||
|
||||
/*-*************************************
|
||||
* Dependencies
|
||||
***************************************/
|
||||
#include "zstd_internal.h"
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
# include "zstdmt_compress.h"
|
||||
#endif
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*-*************************************
|
||||
* Constants
|
||||
***************************************/
|
||||
static const U32 g_searchStrength = 8;
|
||||
#define HASH_READ_SIZE 8
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Context memory management
|
||||
***************************************/
|
||||
typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
|
||||
typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage;
|
||||
|
||||
typedef struct ZSTD_prefixDict_s {
|
||||
const void* dict;
|
||||
size_t dictSize;
|
||||
ZSTD_dictMode_e dictMode;
|
||||
} ZSTD_prefixDict;
|
||||
|
||||
struct ZSTD_CCtx_s {
|
||||
const BYTE* nextSrc; /* next block here to continue on current prefix */
|
||||
const BYTE* base; /* All regular indexes relative to this position */
|
||||
const BYTE* dictBase; /* extDict indexes relative to this position */
|
||||
U32 dictLimit; /* below that point, need extDict */
|
||||
U32 lowLimit; /* below that point, no more data */
|
||||
U32 nextToUpdate; /* index from which to continue dictionary update */
|
||||
U32 nextToUpdate3; /* index from which to continue dictionary update */
|
||||
U32 hashLog3; /* dispatch table : larger == faster, more memory */
|
||||
U32 loadedDictEnd; /* index of end of dictionary */
|
||||
ZSTD_compressionStage_e stage;
|
||||
U32 dictID;
|
||||
ZSTD_CCtx_params requestedParams;
|
||||
ZSTD_CCtx_params appliedParams;
|
||||
void* workSpace;
|
||||
size_t workSpaceSize;
|
||||
size_t blockSize;
|
||||
U64 pledgedSrcSizePlusOne; /* this way, 0 (default) == unknown */
|
||||
U64 consumedSrcSize;
|
||||
XXH64_state_t xxhState;
|
||||
ZSTD_customMem customMem;
|
||||
size_t staticSize;
|
||||
|
||||
seqStore_t seqStore; /* sequences storage ptrs */
|
||||
optState_t optState;
|
||||
ldmState_t ldmState; /* long distance matching state */
|
||||
U32* hashTable;
|
||||
U32* hashTable3;
|
||||
U32* chainTable;
|
||||
ZSTD_entropyCTables_t* entropy;
|
||||
|
||||
/* streaming */
|
||||
char* inBuff;
|
||||
size_t inBuffSize;
|
||||
size_t inToCompress;
|
||||
size_t inBuffPos;
|
||||
size_t inBuffTarget;
|
||||
char* outBuff;
|
||||
size_t outBuffSize;
|
||||
size_t outBuffContentSize;
|
||||
size_t outBuffFlushedSize;
|
||||
ZSTD_cStreamStage streamStage;
|
||||
U32 frameEnded;
|
||||
|
||||
/* Dictionary */
|
||||
ZSTD_CDict* cdictLocal;
|
||||
const ZSTD_CDict* cdict;
|
||||
ZSTD_prefixDict prefixDict; /* single-usage dictionary */
|
||||
|
||||
/* Multi-threading */
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
ZSTDMT_CCtx* mtctx;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 16, 17, 17, 18, 18, 19, 19,
|
||||
20, 20, 20, 20, 21, 21, 21, 21,
|
||||
22, 22, 22, 22, 22, 22, 22, 22,
|
||||
23, 23, 23, 23, 23, 23, 23, 23,
|
||||
24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24 };
|
||||
|
||||
static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
|
||||
38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
|
||||
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
|
||||
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
|
||||
|
||||
/*! ZSTD_storeSeq() :
|
||||
Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
|
||||
`offsetCode` : distance to match, or 0 == repCode.
|
||||
`matchCode` : matchLength - MINMATCH
|
||||
*/
|
||||
MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode)
|
||||
{
|
||||
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6)
|
||||
static const BYTE* g_start = NULL;
|
||||
U32 const pos = (U32)((const BYTE*)literals - g_start);
|
||||
if (g_start==NULL) g_start = (const BYTE*)literals;
|
||||
if ((pos > 0) && (pos < 1000000000))
|
||||
DEBUGLOG(6, "Cpos %6u :%5u literals & match %3u bytes at distance %6u",
|
||||
pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
|
||||
#endif
|
||||
/* copy Literals */
|
||||
assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + 128 KB);
|
||||
ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
|
||||
seqStorePtr->lit += litLength;
|
||||
|
||||
/* literal Length */
|
||||
if (litLength>0xFFFF) {
|
||||
seqStorePtr->longLengthID = 1;
|
||||
seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
|
||||
}
|
||||
seqStorePtr->sequences[0].litLength = (U16)litLength;
|
||||
|
||||
/* match offset */
|
||||
seqStorePtr->sequences[0].offset = offsetCode + 1;
|
||||
|
||||
/* match Length */
|
||||
if (matchCode>0xFFFF) {
|
||||
seqStorePtr->longLengthID = 2;
|
||||
seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
|
||||
}
|
||||
seqStorePtr->sequences[0].matchLength = (U16)matchCode;
|
||||
|
||||
seqStorePtr->sequences++;
|
||||
}
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Match length counter
|
||||
***************************************/
|
||||
static unsigned ZSTD_NbCommonBytes (register size_t val)
|
||||
{
|
||||
if (MEM_isLittleEndian()) {
|
||||
if (MEM_64bits()) {
|
||||
# if defined(_MSC_VER) && defined(_WIN64)
|
||||
unsigned long r = 0;
|
||||
_BitScanForward64( &r, (U64)val );
|
||||
return (unsigned)(r>>3);
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 4)
|
||||
return (__builtin_ctzll((U64)val) >> 3);
|
||||
# else
|
||||
static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
|
||||
0, 3, 1, 3, 1, 4, 2, 7,
|
||||
0, 2, 3, 6, 1, 5, 3, 5,
|
||||
1, 3, 4, 4, 2, 5, 6, 7,
|
||||
7, 0, 1, 2, 3, 3, 4, 6,
|
||||
2, 6, 5, 5, 3, 4, 5, 6,
|
||||
7, 1, 2, 4, 6, 4, 4, 5,
|
||||
7, 2, 6, 5, 7, 6, 7, 7 };
|
||||
return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
|
||||
# endif
|
||||
} else { /* 32 bits */
|
||||
# if defined(_MSC_VER)
|
||||
unsigned long r=0;
|
||||
_BitScanForward( &r, (U32)val );
|
||||
return (unsigned)(r>>3);
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 3)
|
||||
return (__builtin_ctz((U32)val) >> 3);
|
||||
# else
|
||||
static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
|
||||
3, 2, 2, 1, 3, 2, 0, 1,
|
||||
3, 3, 1, 2, 2, 2, 2, 0,
|
||||
3, 1, 2, 0, 1, 0, 1, 1 };
|
||||
return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
|
||||
# endif
|
||||
}
|
||||
} else { /* Big Endian CPU */
|
||||
if (MEM_64bits()) {
|
||||
# if defined(_MSC_VER) && defined(_WIN64)
|
||||
unsigned long r = 0;
|
||||
_BitScanReverse64( &r, val );
|
||||
return (unsigned)(r>>3);
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 4)
|
||||
return (__builtin_clzll(val) >> 3);
|
||||
# else
|
||||
unsigned r;
|
||||
const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
|
||||
if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
|
||||
if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
|
||||
r += (!val);
|
||||
return r;
|
||||
# endif
|
||||
} else { /* 32 bits */
|
||||
# if defined(_MSC_VER)
|
||||
unsigned long r = 0;
|
||||
_BitScanReverse( &r, (unsigned long)val );
|
||||
return (unsigned)(r>>3);
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 3)
|
||||
return (__builtin_clz((U32)val) >> 3);
|
||||
# else
|
||||
unsigned r;
|
||||
if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
|
||||
r += (!val);
|
||||
return r;
|
||||
# endif
|
||||
} }
|
||||
}
|
||||
|
||||
|
||||
MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
|
||||
{
|
||||
const BYTE* const pStart = pIn;
|
||||
const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
|
||||
|
||||
while (pIn < pInLoopLimit) {
|
||||
size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
|
||||
if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
|
||||
pIn += ZSTD_NbCommonBytes(diff);
|
||||
return (size_t)(pIn - pStart);
|
||||
}
|
||||
if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
|
||||
if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
|
||||
if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
|
||||
return (size_t)(pIn - pStart);
|
||||
}
|
||||
|
||||
/** ZSTD_count_2segments() :
|
||||
* can count match length with `ip` & `match` in 2 different segments.
|
||||
* convention : on reaching mEnd, match count continue starting from iStart
|
||||
*/
|
||||
MEM_STATIC size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
|
||||
{
|
||||
const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
|
||||
size_t const matchLength = ZSTD_count(ip, match, vEnd);
|
||||
if (match + matchLength != mEnd) return matchLength;
|
||||
return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
|
||||
}
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Hashes
|
||||
***************************************/
|
||||
static const U32 prime3bytes = 506832829U;
|
||||
static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
|
||||
MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
|
||||
|
||||
static const U32 prime4bytes = 2654435761U;
|
||||
static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
|
||||
static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
|
||||
|
||||
static const U64 prime5bytes = 889523592379ULL;
|
||||
static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
|
||||
|
||||
static const U64 prime6bytes = 227718039650203ULL;
|
||||
static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
|
||||
|
||||
static const U64 prime7bytes = 58295818150454627ULL;
|
||||
static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
|
||||
|
||||
static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
|
||||
static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
|
||||
static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
|
||||
|
||||
MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
|
||||
{
|
||||
switch(mls)
|
||||
{
|
||||
default:
|
||||
case 4: return ZSTD_hash4Ptr(p, hBits);
|
||||
case 5: return ZSTD_hash5Ptr(p, hBits);
|
||||
case 6: return ZSTD_hash6Ptr(p, hBits);
|
||||
case 7: return ZSTD_hash7Ptr(p, hBits);
|
||||
case 8: return ZSTD_hash8Ptr(p, hBits);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZSTD_COMPRESS_H */
|
||||
@@ -1,308 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#include "zstd_double_fast.h"
|
||||
|
||||
|
||||
void ZSTD_fillDoubleHashTable(ZSTD_CCtx* cctx, const void* end, const U32 mls)
|
||||
{
|
||||
U32* const hashLarge = cctx->hashTable;
|
||||
U32 const hBitsL = cctx->appliedParams.cParams.hashLog;
|
||||
U32* const hashSmall = cctx->chainTable;
|
||||
U32 const hBitsS = cctx->appliedParams.cParams.chainLog;
|
||||
const BYTE* const base = cctx->base;
|
||||
const BYTE* ip = base + cctx->nextToUpdate;
|
||||
const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
|
||||
const size_t fastHashFillStep = 3;
|
||||
|
||||
while(ip <= iend) {
|
||||
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
|
||||
hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
|
||||
ip += fastHashFillStep;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
size_t ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
|
||||
const void* src, size_t srcSize,
|
||||
const U32 mls)
|
||||
{
|
||||
U32* const hashLong = cctx->hashTable;
|
||||
const U32 hBitsL = cctx->appliedParams.cParams.hashLog;
|
||||
U32* const hashSmall = cctx->chainTable;
|
||||
const U32 hBitsS = cctx->appliedParams.cParams.chainLog;
|
||||
seqStore_t* seqStorePtr = &(cctx->seqStore);
|
||||
const BYTE* const base = cctx->base;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 lowestIndex = cctx->dictLimit;
|
||||
const BYTE* const lowest = base + lowestIndex;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - HASH_READ_SIZE;
|
||||
U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
|
||||
U32 offsetSaved = 0;
|
||||
|
||||
/* init */
|
||||
ip += (ip==lowest);
|
||||
{ U32 const maxRep = (U32)(ip-lowest);
|
||||
if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
|
||||
if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
|
||||
}
|
||||
|
||||
/* Main Search Loop */
|
||||
while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
|
||||
size_t mLength;
|
||||
size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
|
||||
size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
|
||||
U32 const current = (U32)(ip-base);
|
||||
U32 const matchIndexL = hashLong[h2];
|
||||
U32 const matchIndexS = hashSmall[h];
|
||||
const BYTE* matchLong = base + matchIndexL;
|
||||
const BYTE* match = base + matchIndexS;
|
||||
hashLong[h2] = hashSmall[h] = current; /* update hash tables */
|
||||
|
||||
assert(offset_1 <= current); /* supposed guaranteed by construction */
|
||||
if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
|
||||
/* favor repcode */
|
||||
mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
|
||||
ip++;
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||
} else {
|
||||
U32 offset;
|
||||
if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
|
||||
mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
|
||||
offset = (U32)(ip-matchLong);
|
||||
while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
|
||||
} else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
|
||||
size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
|
||||
U32 const matchIndexL3 = hashLong[hl3];
|
||||
const BYTE* matchL3 = base + matchIndexL3;
|
||||
hashLong[hl3] = current + 1;
|
||||
if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
|
||||
mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
|
||||
ip++;
|
||||
offset = (U32)(ip-matchL3);
|
||||
while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
|
||||
} else {
|
||||
mLength = ZSTD_count(ip+4, match+4, iend) + 4;
|
||||
offset = (U32)(ip-match);
|
||||
while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
}
|
||||
} else {
|
||||
ip += ((ip-anchor) >> g_searchStrength) + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
}
|
||||
|
||||
/* match found */
|
||||
ip += mLength;
|
||||
anchor = ip;
|
||||
|
||||
if (ip <= ilimit) {
|
||||
/* Fill Table */
|
||||
hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
|
||||
hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
|
||||
hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
|
||||
hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
|
||||
|
||||
/* check immediate repcode */
|
||||
while ( (ip <= ilimit)
|
||||
&& ( (offset_2>0)
|
||||
& (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
|
||||
/* store sequence */
|
||||
size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
||||
{ U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
|
||||
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
|
||||
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
|
||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
|
||||
ip += rLength;
|
||||
anchor = ip;
|
||||
continue; /* faster when present ... (?) */
|
||||
} } }
|
||||
|
||||
/* save reps for next block */
|
||||
seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
|
||||
seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
|
||||
|
||||
/* Return the last literals size */
|
||||
return iend - anchor;
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
const U32 mls = ctx->appliedParams.cParams.searchLength;
|
||||
switch(mls)
|
||||
{
|
||||
default: /* includes case 3 */
|
||||
case 4 :
|
||||
return ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4);
|
||||
case 5 :
|
||||
return ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5);
|
||||
case 6 :
|
||||
return ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6);
|
||||
case 7 :
|
||||
return ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize,
|
||||
const U32 mls)
|
||||
{
|
||||
U32* const hashLong = ctx->hashTable;
|
||||
U32 const hBitsL = ctx->appliedParams.cParams.hashLog;
|
||||
U32* const hashSmall = ctx->chainTable;
|
||||
U32 const hBitsS = ctx->appliedParams.cParams.chainLog;
|
||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
||||
const BYTE* const base = ctx->base;
|
||||
const BYTE* const dictBase = ctx->dictBase;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 lowestIndex = ctx->lowLimit;
|
||||
const BYTE* const dictStart = dictBase + lowestIndex;
|
||||
const U32 dictLimit = ctx->dictLimit;
|
||||
const BYTE* const lowPrefixPtr = base + dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
|
||||
|
||||
/* Search Loop */
|
||||
while (ip < ilimit) { /* < instead of <=, because (ip+1) */
|
||||
const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
|
||||
const U32 matchIndex = hashSmall[hSmall];
|
||||
const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* match = matchBase + matchIndex;
|
||||
|
||||
const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
|
||||
const U32 matchLongIndex = hashLong[hLong];
|
||||
const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* matchLong = matchLongBase + matchLongIndex;
|
||||
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
|
||||
const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* repMatch = repBase + repIndex;
|
||||
size_t mLength;
|
||||
hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
|
||||
|
||||
if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
|
||||
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
||||
const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
|
||||
ip++;
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||
} else {
|
||||
if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
|
||||
const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
|
||||
const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
|
||||
U32 offset;
|
||||
mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
|
||||
offset = current - matchLongIndex;
|
||||
while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
|
||||
} else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
|
||||
size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
|
||||
U32 const matchIndex3 = hashLong[h3];
|
||||
const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
|
||||
const BYTE* match3 = match3Base + matchIndex3;
|
||||
U32 offset;
|
||||
hashLong[h3] = current + 1;
|
||||
if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
|
||||
const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
|
||||
const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
|
||||
mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
|
||||
ip++;
|
||||
offset = current+1 - matchIndex3;
|
||||
while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
|
||||
} else {
|
||||
const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
|
||||
const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
|
||||
mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
|
||||
offset = current - matchIndex;
|
||||
while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
}
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
|
||||
} else {
|
||||
ip += ((ip-anchor) >> g_searchStrength) + 1;
|
||||
continue;
|
||||
} }
|
||||
|
||||
/* found a match : store it */
|
||||
ip += mLength;
|
||||
anchor = ip;
|
||||
|
||||
if (ip <= ilimit) {
|
||||
/* Fill Table */
|
||||
hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
|
||||
hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
|
||||
hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
|
||||
hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
|
||||
/* check immediate repcode */
|
||||
while (ip <= ilimit) {
|
||||
U32 const current2 = (U32)(ip-base);
|
||||
U32 const repIndex2 = current2 - offset_2;
|
||||
const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
|
||||
if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
|
||||
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
||||
const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
|
||||
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
|
||||
U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
|
||||
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
|
||||
hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
|
||||
ip += repLength2;
|
||||
anchor = ip;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} } }
|
||||
|
||||
/* save reps for next block */
|
||||
seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
|
||||
|
||||
/* Return the last literals size */
|
||||
return iend - anchor;
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
U32 const mls = ctx->appliedParams.cParams.searchLength;
|
||||
switch(mls)
|
||||
{
|
||||
default: /* includes case 3 */
|
||||
case 4 :
|
||||
return ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4);
|
||||
case 5 :
|
||||
return ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5);
|
||||
case 6 :
|
||||
return ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6);
|
||||
case 7 :
|
||||
return ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_DOUBLE_FAST_H
|
||||
#define ZSTD_DOUBLE_FAST_H
|
||||
|
||||
#include "zstd_compress.h"
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void ZSTD_fillDoubleHashTable(ZSTD_CCtx* cctx, const void* end, const U32 mls);
|
||||
size_t ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZSTD_DOUBLE_FAST_H */
|
||||
@@ -1,242 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#include "zstd_fast.h"
|
||||
|
||||
|
||||
void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
|
||||
{
|
||||
U32* const hashTable = zc->hashTable;
|
||||
U32 const hBits = zc->appliedParams.cParams.hashLog;
|
||||
const BYTE* const base = zc->base;
|
||||
const BYTE* ip = base + zc->nextToUpdate;
|
||||
const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
|
||||
const size_t fastHashFillStep = 3;
|
||||
|
||||
while(ip <= iend) {
|
||||
hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
|
||||
ip += fastHashFillStep;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
|
||||
const void* src, size_t srcSize,
|
||||
const U32 mls)
|
||||
{
|
||||
U32* const hashTable = cctx->hashTable;
|
||||
U32 const hBits = cctx->appliedParams.cParams.hashLog;
|
||||
seqStore_t* seqStorePtr = &(cctx->seqStore);
|
||||
const BYTE* const base = cctx->base;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 lowestIndex = cctx->dictLimit;
|
||||
const BYTE* const lowest = base + lowestIndex;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - HASH_READ_SIZE;
|
||||
U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
|
||||
U32 offsetSaved = 0;
|
||||
|
||||
/* init */
|
||||
ip += (ip==lowest);
|
||||
{ U32 const maxRep = (U32)(ip-lowest);
|
||||
if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
|
||||
if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
|
||||
}
|
||||
|
||||
/* Main Search Loop */
|
||||
while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
|
||||
size_t mLength;
|
||||
size_t const h = ZSTD_hashPtr(ip, hBits, mls);
|
||||
U32 const current = (U32)(ip-base);
|
||||
U32 const matchIndex = hashTable[h];
|
||||
const BYTE* match = base + matchIndex;
|
||||
hashTable[h] = current; /* update hash table */
|
||||
|
||||
if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
|
||||
mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
|
||||
ip++;
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||
} else {
|
||||
U32 offset;
|
||||
if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
|
||||
ip += ((ip-anchor) >> g_searchStrength) + 1;
|
||||
continue;
|
||||
}
|
||||
mLength = ZSTD_count(ip+4, match+4, iend) + 4;
|
||||
offset = (U32)(ip-match);
|
||||
while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
}
|
||||
|
||||
/* match found */
|
||||
ip += mLength;
|
||||
anchor = ip;
|
||||
|
||||
if (ip <= ilimit) {
|
||||
/* Fill Table */
|
||||
hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2; /* here because current+2 could be > iend-8 */
|
||||
hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
|
||||
/* check immediate repcode */
|
||||
while ( (ip <= ilimit)
|
||||
&& ( (offset_2>0)
|
||||
& (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
|
||||
/* store sequence */
|
||||
size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
||||
{ U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
|
||||
hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
|
||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
|
||||
ip += rLength;
|
||||
anchor = ip;
|
||||
continue; /* faster when present ... (?) */
|
||||
} } }
|
||||
|
||||
/* save reps for next block */
|
||||
seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
|
||||
seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
|
||||
|
||||
/* Return the last literals size */
|
||||
return iend - anchor;
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
const U32 mls = ctx->appliedParams.cParams.searchLength;
|
||||
switch(mls)
|
||||
{
|
||||
default: /* includes case 3 */
|
||||
case 4 :
|
||||
return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4);
|
||||
case 5 :
|
||||
return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5);
|
||||
case 6 :
|
||||
return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6);
|
||||
case 7 :
|
||||
return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize,
|
||||
const U32 mls)
|
||||
{
|
||||
U32* hashTable = ctx->hashTable;
|
||||
const U32 hBits = ctx->appliedParams.cParams.hashLog;
|
||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
||||
const BYTE* const base = ctx->base;
|
||||
const BYTE* const dictBase = ctx->dictBase;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 lowestIndex = ctx->lowLimit;
|
||||
const BYTE* const dictStart = dictBase + lowestIndex;
|
||||
const U32 dictLimit = ctx->dictLimit;
|
||||
const BYTE* const lowPrefixPtr = base + dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
|
||||
|
||||
/* Search Loop */
|
||||
while (ip < ilimit) { /* < instead of <=, because (ip+1) */
|
||||
const size_t h = ZSTD_hashPtr(ip, hBits, mls);
|
||||
const U32 matchIndex = hashTable[h];
|
||||
const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* match = matchBase + matchIndex;
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
|
||||
const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* repMatch = repBase + repIndex;
|
||||
size_t mLength;
|
||||
hashTable[h] = current; /* update hash table */
|
||||
|
||||
if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
|
||||
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
||||
const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
|
||||
ip++;
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
|
||||
} else {
|
||||
if ( (matchIndex < lowestIndex) ||
|
||||
(MEM_read32(match) != MEM_read32(ip)) ) {
|
||||
ip += ((ip-anchor) >> g_searchStrength) + 1;
|
||||
continue;
|
||||
}
|
||||
{ const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
|
||||
const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
|
||||
U32 offset;
|
||||
mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
|
||||
while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||
offset = current - matchIndex;
|
||||
offset_2 = offset_1;
|
||||
offset_1 = offset;
|
||||
ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
|
||||
} }
|
||||
|
||||
/* found a match : store it */
|
||||
ip += mLength;
|
||||
anchor = ip;
|
||||
|
||||
if (ip <= ilimit) {
|
||||
/* Fill Table */
|
||||
hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
|
||||
hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
|
||||
/* check immediate repcode */
|
||||
while (ip <= ilimit) {
|
||||
U32 const current2 = (U32)(ip-base);
|
||||
U32 const repIndex2 = current2 - offset_2;
|
||||
const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
|
||||
if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
|
||||
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
||||
const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
|
||||
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
|
||||
U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
|
||||
hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
|
||||
ip += repLength2;
|
||||
anchor = ip;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} } }
|
||||
|
||||
/* save reps for next block */
|
||||
seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
|
||||
|
||||
/* Return the last literals size */
|
||||
return iend - anchor;
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
U32 const mls = ctx->appliedParams.cParams.searchLength;
|
||||
switch(mls)
|
||||
{
|
||||
default: /* includes case 3 */
|
||||
case 4 :
|
||||
return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4);
|
||||
case 5 :
|
||||
return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5);
|
||||
case 6 :
|
||||
return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6);
|
||||
case 7 :
|
||||
return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_FAST_H
|
||||
#define ZSTD_FAST_H
|
||||
|
||||
#include "zstd_compress.h"
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void ZSTD_fillHashTable(ZSTD_CCtx* zc, const void* end, const U32 mls);
|
||||
size_t ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZSTD_FAST_H */
|
||||
@@ -1,749 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#include "zstd_lazy.h"
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Binary Tree search
|
||||
***************************************/
|
||||
/** ZSTD_insertBt1() : add one or multiple positions to tree.
|
||||
* ip : assumed <= iend-8 .
|
||||
* @return : nb of positions added */
|
||||
static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
|
||||
U32 extDict)
|
||||
{
|
||||
U32* const hashTable = zc->hashTable;
|
||||
U32 const hashLog = zc->appliedParams.cParams.hashLog;
|
||||
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
|
||||
U32* const bt = zc->chainTable;
|
||||
U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
|
||||
U32 const btMask = (1 << btLog) - 1;
|
||||
U32 matchIndex = hashTable[h];
|
||||
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
||||
const BYTE* const base = zc->base;
|
||||
const BYTE* const dictBase = zc->dictBase;
|
||||
const U32 dictLimit = zc->dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const prefixStart = base + dictLimit;
|
||||
const BYTE* match;
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 btLow = btMask >= current ? 0 : current - btMask;
|
||||
U32* smallerPtr = bt + 2*(current&btMask);
|
||||
U32* largerPtr = smallerPtr + 1;
|
||||
U32 dummy32; /* to be nullified at the end */
|
||||
U32 const windowLow = zc->lowLimit;
|
||||
U32 matchEndIdx = current+8;
|
||||
size_t bestLength = 8;
|
||||
#ifdef ZSTD_C_PREDICT
|
||||
U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
|
||||
U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
|
||||
predictedSmall += (predictedSmall>0);
|
||||
predictedLarge += (predictedLarge>0);
|
||||
#endif /* ZSTD_C_PREDICT */
|
||||
|
||||
assert(ip <= iend-8); /* required for h calculation */
|
||||
hashTable[h] = current; /* Update Hash Table */
|
||||
|
||||
while (nbCompares-- && (matchIndex > windowLow)) {
|
||||
U32* const nextPtr = bt + 2*(matchIndex & btMask);
|
||||
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||
|
||||
#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
|
||||
const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
|
||||
if (matchIndex == predictedSmall) {
|
||||
/* no need to check length, result known */
|
||||
*smallerPtr = matchIndex;
|
||||
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||
smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
|
||||
matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
|
||||
predictedSmall = predictPtr[1] + (predictPtr[1]>0);
|
||||
continue;
|
||||
}
|
||||
if (matchIndex == predictedLarge) {
|
||||
*largerPtr = matchIndex;
|
||||
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||
largerPtr = nextPtr;
|
||||
matchIndex = nextPtr[0];
|
||||
predictedLarge = predictPtr[0] + (predictPtr[0]>0);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
|
||||
match = base + matchIndex;
|
||||
if (match[matchLength] == ip[matchLength])
|
||||
matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
|
||||
} else {
|
||||
match = dictBase + matchIndex;
|
||||
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
|
||||
if (matchIndex+matchLength >= dictLimit)
|
||||
match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
|
||||
}
|
||||
|
||||
if (matchLength > bestLength) {
|
||||
bestLength = matchLength;
|
||||
if (matchLength > matchEndIdx - matchIndex)
|
||||
matchEndIdx = matchIndex + (U32)matchLength;
|
||||
}
|
||||
|
||||
if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
|
||||
break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
|
||||
|
||||
if (match[matchLength] < ip[matchLength]) { /* necessarily within buffer */
|
||||
/* match+1 is smaller than current */
|
||||
*smallerPtr = matchIndex; /* update smaller idx */
|
||||
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
|
||||
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
|
||||
smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
|
||||
matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
|
||||
} else {
|
||||
/* match is larger than current */
|
||||
*largerPtr = matchIndex;
|
||||
commonLengthLarger = matchLength;
|
||||
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
|
||||
largerPtr = nextPtr;
|
||||
matchIndex = nextPtr[0];
|
||||
} }
|
||||
|
||||
*smallerPtr = *largerPtr = 0;
|
||||
if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
|
||||
if (matchEndIdx > current + 8) return matchEndIdx - (current + 8);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_insertBtAndFindBestMatch (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* const ip, const BYTE* const iend,
|
||||
size_t* offsetPtr,
|
||||
U32 nbCompares, const U32 mls,
|
||||
U32 extDict)
|
||||
{
|
||||
U32* const hashTable = zc->hashTable;
|
||||
U32 const hashLog = zc->appliedParams.cParams.hashLog;
|
||||
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
|
||||
U32* const bt = zc->chainTable;
|
||||
U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
|
||||
U32 const btMask = (1 << btLog) - 1;
|
||||
U32 matchIndex = hashTable[h];
|
||||
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
||||
const BYTE* const base = zc->base;
|
||||
const BYTE* const dictBase = zc->dictBase;
|
||||
const U32 dictLimit = zc->dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const prefixStart = base + dictLimit;
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 btLow = btMask >= current ? 0 : current - btMask;
|
||||
const U32 windowLow = zc->lowLimit;
|
||||
U32* smallerPtr = bt + 2*(current&btMask);
|
||||
U32* largerPtr = bt + 2*(current&btMask) + 1;
|
||||
U32 matchEndIdx = current+8;
|
||||
U32 dummy32; /* to be nullified at the end */
|
||||
size_t bestLength = 0;
|
||||
|
||||
assert(ip <= iend-8); /* required for h calculation */
|
||||
hashTable[h] = current; /* Update Hash Table */
|
||||
|
||||
while (nbCompares-- && (matchIndex > windowLow)) {
|
||||
U32* const nextPtr = bt + 2*(matchIndex & btMask);
|
||||
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||
const BYTE* match;
|
||||
|
||||
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
|
||||
match = base + matchIndex;
|
||||
if (match[matchLength] == ip[matchLength])
|
||||
matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
|
||||
} else {
|
||||
match = dictBase + matchIndex;
|
||||
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
|
||||
if (matchIndex+matchLength >= dictLimit)
|
||||
match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
|
||||
}
|
||||
|
||||
if (matchLength > bestLength) {
|
||||
if (matchLength > matchEndIdx - matchIndex)
|
||||
matchEndIdx = matchIndex + (U32)matchLength;
|
||||
if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
|
||||
bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
|
||||
if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
|
||||
break; /* drop, to guarantee consistency (miss a little bit of compression) */
|
||||
}
|
||||
|
||||
if (match[matchLength] < ip[matchLength]) {
|
||||
/* match is smaller than current */
|
||||
*smallerPtr = matchIndex; /* update smaller idx */
|
||||
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
|
||||
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||
smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
|
||||
matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
|
||||
} else {
|
||||
/* match is larger than current */
|
||||
*largerPtr = matchIndex;
|
||||
commonLengthLarger = matchLength;
|
||||
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||
largerPtr = nextPtr;
|
||||
matchIndex = nextPtr[0];
|
||||
} }
|
||||
|
||||
*smallerPtr = *largerPtr = 0;
|
||||
|
||||
zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
|
||||
return bestLength;
|
||||
}
|
||||
|
||||
|
||||
void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
|
||||
{
|
||||
const BYTE* const base = zc->base;
|
||||
const U32 target = (U32)(ip - base);
|
||||
U32 idx = zc->nextToUpdate;
|
||||
|
||||
while(idx < target)
|
||||
idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
|
||||
}
|
||||
|
||||
/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
|
||||
static size_t ZSTD_BtFindBestMatch (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 maxNbAttempts, const U32 mls)
|
||||
{
|
||||
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
|
||||
ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
|
||||
return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_BtFindBestMatch_selectMLS (
|
||||
ZSTD_CCtx* zc, /* Index table will be updated */
|
||||
const BYTE* ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 maxNbAttempts, const U32 matchLengthSearch)
|
||||
{
|
||||
switch(matchLengthSearch)
|
||||
{
|
||||
default : /* includes case 3 */
|
||||
case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
|
||||
case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
|
||||
{
|
||||
const BYTE* const base = zc->base;
|
||||
const U32 target = (U32)(ip - base);
|
||||
U32 idx = zc->nextToUpdate;
|
||||
|
||||
while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
|
||||
}
|
||||
|
||||
|
||||
/** Tree updater, providing best match */
|
||||
static size_t ZSTD_BtFindBestMatch_extDict (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 maxNbAttempts, const U32 mls)
|
||||
{
|
||||
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
|
||||
ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
|
||||
return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
|
||||
ZSTD_CCtx* zc, /* Index table will be updated */
|
||||
const BYTE* ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 maxNbAttempts, const U32 matchLengthSearch)
|
||||
{
|
||||
switch(matchLengthSearch)
|
||||
{
|
||||
default : /* includes case 3 */
|
||||
case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
|
||||
case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* *********************************
|
||||
* Hash Chain
|
||||
***********************************/
|
||||
#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
|
||||
|
||||
/* Update chains up to ip (excluded)
|
||||
Assumption : always within prefix (i.e. not within extDict) */
|
||||
U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
|
||||
{
|
||||
U32* const hashTable = zc->hashTable;
|
||||
const U32 hashLog = zc->appliedParams.cParams.hashLog;
|
||||
U32* const chainTable = zc->chainTable;
|
||||
const U32 chainMask = (1 << zc->appliedParams.cParams.chainLog) - 1;
|
||||
const BYTE* const base = zc->base;
|
||||
const U32 target = (U32)(ip - base);
|
||||
U32 idx = zc->nextToUpdate;
|
||||
|
||||
while(idx < target) { /* catch up */
|
||||
size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
|
||||
NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
|
||||
hashTable[h] = idx;
|
||||
idx++;
|
||||
}
|
||||
|
||||
zc->nextToUpdate = target;
|
||||
return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
|
||||
}
|
||||
|
||||
|
||||
/* inlining is important to hardwire a hot branch (template emulation) */
|
||||
FORCE_INLINE_TEMPLATE
|
||||
size_t ZSTD_HcFindBestMatch_generic (
|
||||
ZSTD_CCtx* zc, /* Index table will be updated */
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 maxNbAttempts, const U32 mls, const U32 extDict)
|
||||
{
|
||||
U32* const chainTable = zc->chainTable;
|
||||
const U32 chainSize = (1 << zc->appliedParams.cParams.chainLog);
|
||||
const U32 chainMask = chainSize-1;
|
||||
const BYTE* const base = zc->base;
|
||||
const BYTE* const dictBase = zc->dictBase;
|
||||
const U32 dictLimit = zc->dictLimit;
|
||||
const BYTE* const prefixStart = base + dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const U32 lowLimit = zc->lowLimit;
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 minChain = current > chainSize ? current - chainSize : 0;
|
||||
int nbAttempts=maxNbAttempts;
|
||||
size_t ml=4-1;
|
||||
|
||||
/* HC4 match finder */
|
||||
U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
|
||||
|
||||
for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
|
||||
const BYTE* match;
|
||||
size_t currentMl=0;
|
||||
if ((!extDict) || matchIndex >= dictLimit) {
|
||||
match = base + matchIndex;
|
||||
if (match[ml] == ip[ml]) /* potentially better */
|
||||
currentMl = ZSTD_count(ip, match, iLimit);
|
||||
} else {
|
||||
match = dictBase + matchIndex;
|
||||
if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
|
||||
currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
|
||||
}
|
||||
|
||||
/* save best solution */
|
||||
if (currentMl > ml) {
|
||||
ml = currentMl;
|
||||
*offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
|
||||
if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
|
||||
}
|
||||
|
||||
if (matchIndex <= minChain) break;
|
||||
matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
|
||||
}
|
||||
|
||||
return ml;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 maxNbAttempts, const U32 matchLengthSearch)
|
||||
{
|
||||
switch(matchLengthSearch)
|
||||
{
|
||||
default : /* includes case 3 */
|
||||
case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
|
||||
case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* ip, const BYTE* const iLimit,
|
||||
size_t* offsetPtr,
|
||||
const U32 maxNbAttempts, const U32 matchLengthSearch)
|
||||
{
|
||||
switch(matchLengthSearch)
|
||||
{
|
||||
default : /* includes case 3 */
|
||||
case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
|
||||
case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* *******************************
|
||||
* Common parser - lazy strategy
|
||||
*********************************/
|
||||
FORCE_INLINE_TEMPLATE
|
||||
size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize,
|
||||
const U32 searchMethod, const U32 depth)
|
||||
{
|
||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
const BYTE* const base = ctx->base + ctx->dictLimit;
|
||||
|
||||
U32 const maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
|
||||
U32 const mls = ctx->appliedParams.cParams.searchLength;
|
||||
|
||||
typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
|
||||
size_t* offsetPtr,
|
||||
U32 maxNbAttempts, U32 matchLengthSearch);
|
||||
searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
|
||||
U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1], savedOffset=0;
|
||||
|
||||
/* init */
|
||||
ip += (ip==base);
|
||||
ctx->nextToUpdate3 = ctx->nextToUpdate;
|
||||
{ U32 const maxRep = (U32)(ip-base);
|
||||
if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
|
||||
if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
|
||||
}
|
||||
|
||||
/* Match Loop */
|
||||
while (ip < ilimit) {
|
||||
size_t matchLength=0;
|
||||
size_t offset=0;
|
||||
const BYTE* start=ip+1;
|
||||
|
||||
/* check repCode */
|
||||
if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
|
||||
/* repcode : we take it */
|
||||
matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
|
||||
if (depth==0) goto _storeSequence;
|
||||
}
|
||||
|
||||
/* first search (depth 0) */
|
||||
{ size_t offsetFound = 99999999;
|
||||
size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
|
||||
if (ml2 > matchLength)
|
||||
matchLength = ml2, start = ip, offset=offsetFound;
|
||||
}
|
||||
|
||||
if (matchLength < 4) {
|
||||
ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* let's try to find a better solution */
|
||||
if (depth>=1)
|
||||
while (ip<ilimit) {
|
||||
ip ++;
|
||||
if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
|
||||
size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
|
||||
int const gain2 = (int)(mlRep * 3);
|
||||
int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
|
||||
if ((mlRep >= 4) && (gain2 > gain1))
|
||||
matchLength = mlRep, offset = 0, start = ip;
|
||||
}
|
||||
{ size_t offset2=99999999;
|
||||
size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
|
||||
int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
|
||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
|
||||
if ((ml2 >= 4) && (gain2 > gain1)) {
|
||||
matchLength = ml2, offset = offset2, start = ip;
|
||||
continue; /* search a better one */
|
||||
} }
|
||||
|
||||
/* let's find an even better one */
|
||||
if ((depth==2) && (ip<ilimit)) {
|
||||
ip ++;
|
||||
if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
|
||||
size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
|
||||
int const gain2 = (int)(ml2 * 4);
|
||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
|
||||
if ((ml2 >= 4) && (gain2 > gain1))
|
||||
matchLength = ml2, offset = 0, start = ip;
|
||||
}
|
||||
{ size_t offset2=99999999;
|
||||
size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
|
||||
int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
|
||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
|
||||
if ((ml2 >= 4) && (gain2 > gain1)) {
|
||||
matchLength = ml2, offset = offset2, start = ip;
|
||||
continue;
|
||||
} } }
|
||||
break; /* nothing found : store previous solution */
|
||||
}
|
||||
|
||||
/* NOTE:
|
||||
* start[-offset+ZSTD_REP_MOVE-1] is undefined behavior.
|
||||
* (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which
|
||||
* overflows the pointer, which is undefined behavior.
|
||||
*/
|
||||
/* catch up */
|
||||
if (offset) {
|
||||
while ( (start > anchor)
|
||||
&& (start > base+offset-ZSTD_REP_MOVE)
|
||||
&& (start[-1] == (start-offset+ZSTD_REP_MOVE)[-1]) ) /* only search for offset within prefix */
|
||||
{ start--; matchLength++; }
|
||||
offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
|
||||
}
|
||||
/* store sequence */
|
||||
_storeSequence:
|
||||
{ size_t const litLength = start - anchor;
|
||||
ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
|
||||
anchor = ip = start + matchLength;
|
||||
}
|
||||
|
||||
/* check immediate repcode */
|
||||
while ( (ip <= ilimit)
|
||||
&& ((offset_2>0)
|
||||
& (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
|
||||
/* store sequence */
|
||||
matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
|
||||
offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
|
||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
|
||||
ip += matchLength;
|
||||
anchor = ip;
|
||||
continue; /* faster when present ... (?) */
|
||||
} }
|
||||
|
||||
/* Save reps for next block */
|
||||
seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
|
||||
seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
|
||||
|
||||
/* Return the last literals size */
|
||||
return iend - anchor;
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize,
|
||||
const U32 searchMethod, const U32 depth)
|
||||
{
|
||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
const BYTE* const base = ctx->base;
|
||||
const U32 dictLimit = ctx->dictLimit;
|
||||
const U32 lowestIndex = ctx->lowLimit;
|
||||
const BYTE* const prefixStart = base + dictLimit;
|
||||
const BYTE* const dictBase = ctx->dictBase;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const dictStart = dictBase + ctx->lowLimit;
|
||||
|
||||
const U32 maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
|
||||
const U32 mls = ctx->appliedParams.cParams.searchLength;
|
||||
|
||||
typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
|
||||
size_t* offsetPtr,
|
||||
U32 maxNbAttempts, U32 matchLengthSearch);
|
||||
searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
|
||||
|
||||
U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1];
|
||||
|
||||
/* init */
|
||||
ctx->nextToUpdate3 = ctx->nextToUpdate;
|
||||
ip += (ip == prefixStart);
|
||||
|
||||
/* Match Loop */
|
||||
while (ip < ilimit) {
|
||||
size_t matchLength=0;
|
||||
size_t offset=0;
|
||||
const BYTE* start=ip+1;
|
||||
U32 current = (U32)(ip-base);
|
||||
|
||||
/* check repCode */
|
||||
{ const U32 repIndex = (U32)(current+1 - offset_1);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
|
||||
if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
|
||||
/* repcode detected we should take it */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
|
||||
if (depth==0) goto _storeSequence;
|
||||
} }
|
||||
|
||||
/* first search (depth 0) */
|
||||
{ size_t offsetFound = 99999999;
|
||||
size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
|
||||
if (ml2 > matchLength)
|
||||
matchLength = ml2, start = ip, offset=offsetFound;
|
||||
}
|
||||
|
||||
if (matchLength < 4) {
|
||||
ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* let's try to find a better solution */
|
||||
if (depth>=1)
|
||||
while (ip<ilimit) {
|
||||
ip ++;
|
||||
current++;
|
||||
/* check repCode */
|
||||
if (offset) {
|
||||
const U32 repIndex = (U32)(current - offset_1);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
|
||||
if (MEM_read32(ip) == MEM_read32(repMatch)) {
|
||||
/* repcode detected */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
|
||||
int const gain2 = (int)(repLength * 3);
|
||||
int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
|
||||
if ((repLength >= 4) && (gain2 > gain1))
|
||||
matchLength = repLength, offset = 0, start = ip;
|
||||
} }
|
||||
|
||||
/* search match, depth 1 */
|
||||
{ size_t offset2=99999999;
|
||||
size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
|
||||
int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
|
||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
|
||||
if ((ml2 >= 4) && (gain2 > gain1)) {
|
||||
matchLength = ml2, offset = offset2, start = ip;
|
||||
continue; /* search a better one */
|
||||
} }
|
||||
|
||||
/* let's find an even better one */
|
||||
if ((depth==2) && (ip<ilimit)) {
|
||||
ip ++;
|
||||
current++;
|
||||
/* check repCode */
|
||||
if (offset) {
|
||||
const U32 repIndex = (U32)(current - offset_1);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
|
||||
if (MEM_read32(ip) == MEM_read32(repMatch)) {
|
||||
/* repcode detected */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
|
||||
int const gain2 = (int)(repLength * 4);
|
||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
|
||||
if ((repLength >= 4) && (gain2 > gain1))
|
||||
matchLength = repLength, offset = 0, start = ip;
|
||||
} }
|
||||
|
||||
/* search match, depth 2 */
|
||||
{ size_t offset2=99999999;
|
||||
size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
|
||||
int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
|
||||
int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
|
||||
if ((ml2 >= 4) && (gain2 > gain1)) {
|
||||
matchLength = ml2, offset = offset2, start = ip;
|
||||
continue;
|
||||
} } }
|
||||
break; /* nothing found : store previous solution */
|
||||
}
|
||||
|
||||
/* catch up */
|
||||
if (offset) {
|
||||
U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
|
||||
const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
|
||||
const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
|
||||
while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
|
||||
offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
|
||||
}
|
||||
|
||||
/* store sequence */
|
||||
_storeSequence:
|
||||
{ size_t const litLength = start - anchor;
|
||||
ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
|
||||
anchor = ip = start + matchLength;
|
||||
}
|
||||
|
||||
/* check immediate repcode */
|
||||
while (ip <= ilimit) {
|
||||
const U32 repIndex = (U32)((ip-base) - offset_2);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
|
||||
if (MEM_read32(ip) == MEM_read32(repMatch)) {
|
||||
/* repcode detected we should take it */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
|
||||
offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
|
||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
|
||||
ip += matchLength;
|
||||
anchor = ip;
|
||||
continue; /* faster when present ... (?) */
|
||||
}
|
||||
break;
|
||||
} }
|
||||
|
||||
/* Save reps for next block */
|
||||
seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
|
||||
|
||||
/* Return the last literals size */
|
||||
return iend - anchor;
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_LAZY_H
|
||||
#define ZSTD_LAZY_H
|
||||
|
||||
#include "zstd_compress.h"
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls);
|
||||
void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls);
|
||||
void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls);
|
||||
|
||||
size_t ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
|
||||
size_t ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZSTD_LAZY_H */
|
||||
@@ -1,703 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
*/
|
||||
|
||||
#include "zstd_ldm.h"
|
||||
|
||||
#include "zstd_fast.h" /* ZSTD_fillHashTable() */
|
||||
#include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */
|
||||
|
||||
#define LDM_BUCKET_SIZE_LOG 3
|
||||
#define LDM_MIN_MATCH_LENGTH 64
|
||||
#define LDM_HASH_LOG 20
|
||||
#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->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
|
||||
params->minMatchLength = LDM_MIN_MATCH_LENGTH;
|
||||
params->hashEveryLog = ZSTD_LDM_HASHEVERYLOG_NOTSET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ZSTD_ldm_adjustParameters(ldmParams_t* params, U32 windowLog)
|
||||
{
|
||||
if (params->hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET) {
|
||||
params->hashEveryLog =
|
||||
windowLog < params->hashLog ? 0 : windowLog - params->hashLog;
|
||||
}
|
||||
params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog);
|
||||
}
|
||||
|
||||
size_t ZSTD_ldm_getTableSize(U32 hashLog, U32 bucketSizeLog) {
|
||||
size_t const ldmHSize = ((size_t)1) << hashLog;
|
||||
size_t const ldmBucketSizeLog = MIN(bucketSizeLog, hashLog);
|
||||
size_t const ldmBucketSize =
|
||||
((size_t)1) << (hashLog - ldmBucketSizeLog);
|
||||
return ldmBucketSize + (ldmHSize * (sizeof(ldmEntry_t)));
|
||||
}
|
||||
|
||||
/** ZSTD_ldm_getSmallHash() :
|
||||
* numBits should be <= 32
|
||||
* If numBits==0, returns 0.
|
||||
* @return : the most significant numBits of value. */
|
||||
static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits)
|
||||
{
|
||||
assert(numBits <= 32);
|
||||
return numBits == 0 ? 0 : (U32)(value >> (64 - numBits));
|
||||
}
|
||||
|
||||
/** ZSTD_ldm_getChecksum() :
|
||||
* numBitsToDiscard should be <= 32
|
||||
* @return : the next most significant 32 bits after numBitsToDiscard */
|
||||
static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard)
|
||||
{
|
||||
assert(numBitsToDiscard <= 32);
|
||||
return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
/** ZSTD_ldm_getTag() ;
|
||||
* Given the hash, returns the most significant numTagBits bits
|
||||
* after (32 + hbits) bits.
|
||||
*
|
||||
* If there are not enough bits remaining, return the last
|
||||
* numTagBits bits. */
|
||||
static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits)
|
||||
{
|
||||
assert(numTagBits < 32 && hbits <= 32);
|
||||
if (32 - hbits < numTagBits) {
|
||||
return hash & (((U32)1 << numTagBits) - 1);
|
||||
} else {
|
||||
return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/** ZSTD_ldm_getBucket() :
|
||||
* Returns a pointer to the start of the bucket associated with hash. */
|
||||
static ldmEntry_t* ZSTD_ldm_getBucket(
|
||||
ldmState_t* ldmState, size_t hash, ldmParams_t const ldmParams)
|
||||
{
|
||||
return ldmState->hashTable + (hash << ldmParams.bucketSizeLog);
|
||||
}
|
||||
|
||||
/** ZSTD_ldm_insertEntry() :
|
||||
* Insert the entry with corresponding hash into the hash table */
|
||||
static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
|
||||
size_t const hash, const ldmEntry_t entry,
|
||||
ldmParams_t const ldmParams)
|
||||
{
|
||||
BYTE* const bucketOffsets = ldmState->bucketOffsets;
|
||||
*(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry;
|
||||
bucketOffsets[hash]++;
|
||||
bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1;
|
||||
}
|
||||
|
||||
/** ZSTD_ldm_makeEntryAndInsertByTag() :
|
||||
*
|
||||
* Gets the small hash, checksum, and tag from the rollingHash.
|
||||
*
|
||||
* If the tag matches (1 << ldmParams.hashEveryLog)-1, then
|
||||
* creates an ldmEntry from the offset, and inserts it into the hash table.
|
||||
*
|
||||
* hBits is the length of the small hash, which is the most significant hBits
|
||||
* of rollingHash. The checksum is the next 32 most significant bits, followed
|
||||
* by ldmParams.hashEveryLog bits that make up the tag. */
|
||||
static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
|
||||
U64 const rollingHash,
|
||||
U32 const hBits,
|
||||
U32 const offset,
|
||||
ldmParams_t const ldmParams)
|
||||
{
|
||||
U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog);
|
||||
U32 const tagMask = ((U32)1 << ldmParams.hashEveryLog) - 1;
|
||||
if (tag == tagMask) {
|
||||
U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits);
|
||||
U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
|
||||
ldmEntry_t entry;
|
||||
entry.offset = offset;
|
||||
entry.checksum = checksum;
|
||||
ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams);
|
||||
}
|
||||
}
|
||||
|
||||
/** ZSTD_ldm_getRollingHash() :
|
||||
* Get a 64-bit hash using the first len bytes from buf.
|
||||
*
|
||||
* Giving bytes s = s_1, s_2, ... s_k, the hash is defined to be
|
||||
* H(s) = s_1*(a^(k-1)) + s_2*(a^(k-2)) + ... + s_k*(a^0)
|
||||
*
|
||||
* where the constant a is defined to be prime8bytes.
|
||||
*
|
||||
* The implementation adds an offset to each byte, so
|
||||
* H(s) = (s_1 + HASH_CHAR_OFFSET)*(a^(k-1)) + ... */
|
||||
static U64 ZSTD_ldm_getRollingHash(const BYTE* buf, U32 len)
|
||||
{
|
||||
U64 ret = 0;
|
||||
U32 i;
|
||||
for (i = 0; i < len; i++) {
|
||||
ret *= prime8bytes;
|
||||
ret += buf[i] + LDM_HASH_CHAR_OFFSET;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** ZSTD_ldm_ipow() :
|
||||
* Return base^exp. */
|
||||
static U64 ZSTD_ldm_ipow(U64 base, U64 exp)
|
||||
{
|
||||
U64 ret = 1;
|
||||
while (exp) {
|
||||
if (exp & 1) { ret *= base; }
|
||||
exp >>= 1;
|
||||
base *= base;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
U64 ZSTD_ldm_getHashPower(U32 minMatchLength) {
|
||||
assert(minMatchLength >= ZSTD_LDM_MINMATCH_MIN);
|
||||
return ZSTD_ldm_ipow(prime8bytes, minMatchLength - 1);
|
||||
}
|
||||
|
||||
/** ZSTD_ldm_updateHash() :
|
||||
* Updates hash by removing toRemove and adding toAdd. */
|
||||
static U64 ZSTD_ldm_updateHash(U64 hash, BYTE toRemove, BYTE toAdd, U64 hashPower)
|
||||
{
|
||||
hash -= ((toRemove + LDM_HASH_CHAR_OFFSET) * hashPower);
|
||||
hash *= prime8bytes;
|
||||
hash += toAdd + LDM_HASH_CHAR_OFFSET;
|
||||
return hash;
|
||||
}
|
||||
|
||||
/** ZSTD_ldm_countBackwardsMatch() :
|
||||
* Returns the number of bytes that match backwards before pIn and pMatch.
|
||||
*
|
||||
* We count only bytes where pMatch >= pBase and pIn >= pAnchor. */
|
||||
static size_t ZSTD_ldm_countBackwardsMatch(
|
||||
const BYTE* pIn, const BYTE* pAnchor,
|
||||
const BYTE* pMatch, const BYTE* pBase)
|
||||
{
|
||||
size_t matchLength = 0;
|
||||
while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) {
|
||||
pIn--;
|
||||
pMatch--;
|
||||
matchLength++;
|
||||
}
|
||||
return matchLength;
|
||||
}
|
||||
|
||||
/** ZSTD_ldm_fillFastTables() :
|
||||
*
|
||||
* Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies.
|
||||
* This is similar to ZSTD_loadDictionaryContent.
|
||||
*
|
||||
* The tables for the other strategies are filled within their
|
||||
* block compressors. */
|
||||
static size_t ZSTD_ldm_fillFastTables(ZSTD_CCtx* zc, const void* end)
|
||||
{
|
||||
const BYTE* const iend = (const BYTE*)end;
|
||||
const U32 mls = zc->appliedParams.cParams.searchLength;
|
||||
|
||||
switch(zc->appliedParams.cParams.strategy)
|
||||
{
|
||||
case ZSTD_fast:
|
||||
ZSTD_fillHashTable(zc, iend, mls);
|
||||
zc->nextToUpdate = (U32)(iend - zc->base);
|
||||
break;
|
||||
|
||||
case ZSTD_dfast:
|
||||
ZSTD_fillDoubleHashTable(zc, iend, mls);
|
||||
zc->nextToUpdate = (U32)(iend - zc->base);
|
||||
break;
|
||||
|
||||
case ZSTD_greedy:
|
||||
case ZSTD_lazy:
|
||||
case ZSTD_lazy2:
|
||||
case ZSTD_btlazy2:
|
||||
case ZSTD_btopt:
|
||||
case ZSTD_btultra:
|
||||
break;
|
||||
default:
|
||||
assert(0); /* not possible : not a valid strategy id */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** ZSTD_ldm_fillLdmHashTable() :
|
||||
*
|
||||
* Fills hashTable from (lastHashed + 1) to iend (non-inclusive).
|
||||
* lastHash is the rolling hash that corresponds to lastHashed.
|
||||
*
|
||||
* Returns the rolling hash corresponding to position iend-1. */
|
||||
static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state,
|
||||
U64 lastHash, const BYTE* lastHashed,
|
||||
const BYTE* iend, const BYTE* base,
|
||||
U32 hBits, ldmParams_t const ldmParams)
|
||||
{
|
||||
U64 rollingHash = lastHash;
|
||||
const BYTE* cur = lastHashed + 1;
|
||||
|
||||
while (cur < iend) {
|
||||
rollingHash = ZSTD_ldm_updateHash(rollingHash, cur[-1],
|
||||
cur[ldmParams.minMatchLength-1],
|
||||
state->hashPower);
|
||||
ZSTD_ldm_makeEntryAndInsertByTag(state,
|
||||
rollingHash, hBits,
|
||||
(U32)(cur - base), ldmParams);
|
||||
++cur;
|
||||
}
|
||||
return rollingHash;
|
||||
}
|
||||
|
||||
|
||||
/** ZSTD_ldm_limitTableUpdate() :
|
||||
*
|
||||
* Sets cctx->nextToUpdate to a position corresponding closer to anchor
|
||||
* if it is far way
|
||||
* (after a long match, only update tables a limited amount). */
|
||||
static void ZSTD_ldm_limitTableUpdate(ZSTD_CCtx* cctx, const BYTE* anchor)
|
||||
{
|
||||
U32 const current = (U32)(anchor - cctx->base);
|
||||
if (current > cctx->nextToUpdate + 1024) {
|
||||
cctx->nextToUpdate =
|
||||
current - MIN(512, current - cctx->nextToUpdate - 1024);
|
||||
}
|
||||
}
|
||||
|
||||
typedef size_t (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
/* defined in zstd_compress.c */
|
||||
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict);
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
ldmState_t* const ldmState = &(cctx->ldmState);
|
||||
const ldmParams_t ldmParams = cctx->appliedParams.ldmParams;
|
||||
const U64 hashPower = ldmState->hashPower;
|
||||
const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog;
|
||||
const U32 ldmBucketSize = ((U32)1 << ldmParams.bucketSizeLog);
|
||||
const U32 ldmTagMask = ((U32)1 << ldmParams.hashEveryLog) - 1;
|
||||
seqStore_t* const seqStorePtr = &(cctx->seqStore);
|
||||
const BYTE* const base = cctx->base;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 lowestIndex = cctx->dictLimit;
|
||||
const BYTE* const lowest = base + lowestIndex;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - ldmParams.minMatchLength;
|
||||
|
||||
const ZSTD_blockCompressor blockCompressor =
|
||||
ZSTD_selectBlockCompressor(cctx->appliedParams.cParams.strategy, 0);
|
||||
U32* const repToConfirm = seqStorePtr->repToConfirm;
|
||||
U32 savedRep[ZSTD_REP_NUM];
|
||||
U64 rollingHash = 0;
|
||||
const BYTE* lastHashed = NULL;
|
||||
size_t i, lastLiterals;
|
||||
|
||||
/* Save seqStorePtr->rep and copy repToConfirm */
|
||||
for (i = 0; i < ZSTD_REP_NUM; i++)
|
||||
savedRep[i] = repToConfirm[i] = seqStorePtr->rep[i];
|
||||
|
||||
/* Main Search Loop */
|
||||
while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
|
||||
size_t mLength;
|
||||
U32 const current = (U32)(ip - base);
|
||||
size_t forwardMatchLength = 0, backwardMatchLength = 0;
|
||||
ldmEntry_t* bestEntry = NULL;
|
||||
if (ip != istart) {
|
||||
rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0],
|
||||
lastHashed[ldmParams.minMatchLength],
|
||||
hashPower);
|
||||
} else {
|
||||
rollingHash = ZSTD_ldm_getRollingHash(ip, ldmParams.minMatchLength);
|
||||
}
|
||||
lastHashed = ip;
|
||||
|
||||
/* Do not insert and do not look for a match */
|
||||
if (ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog) !=
|
||||
ldmTagMask) {
|
||||
ip++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get the best entry and compute the match lengths */
|
||||
{
|
||||
ldmEntry_t* const bucket =
|
||||
ZSTD_ldm_getBucket(ldmState,
|
||||
ZSTD_ldm_getSmallHash(rollingHash, hBits),
|
||||
ldmParams);
|
||||
ldmEntry_t* cur;
|
||||
size_t bestMatchLength = 0;
|
||||
U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
|
||||
|
||||
for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) {
|
||||
const BYTE* const pMatch = cur->offset + base;
|
||||
size_t curForwardMatchLength, curBackwardMatchLength,
|
||||
curTotalMatchLength;
|
||||
if (cur->checksum != checksum || cur->offset <= lowestIndex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
curForwardMatchLength = ZSTD_count(ip, pMatch, iend);
|
||||
if (curForwardMatchLength < ldmParams.minMatchLength) {
|
||||
continue;
|
||||
}
|
||||
curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch(
|
||||
ip, anchor, pMatch, lowest);
|
||||
curTotalMatchLength = curForwardMatchLength +
|
||||
curBackwardMatchLength;
|
||||
|
||||
if (curTotalMatchLength > bestMatchLength) {
|
||||
bestMatchLength = curTotalMatchLength;
|
||||
forwardMatchLength = curForwardMatchLength;
|
||||
backwardMatchLength = curBackwardMatchLength;
|
||||
bestEntry = cur;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* No match found -- continue searching */
|
||||
if (bestEntry == NULL) {
|
||||
ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash,
|
||||
hBits, current,
|
||||
ldmParams);
|
||||
ip++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Match found */
|
||||
mLength = forwardMatchLength + backwardMatchLength;
|
||||
ip -= backwardMatchLength;
|
||||
|
||||
/* Call the block compressor on the remaining literals */
|
||||
{
|
||||
U32 const matchIndex = bestEntry->offset;
|
||||
const BYTE* const match = base + matchIndex - backwardMatchLength;
|
||||
U32 const offset = (U32)(ip - match);
|
||||
|
||||
/* Overwrite rep codes */
|
||||
for (i = 0; i < ZSTD_REP_NUM; i++)
|
||||
seqStorePtr->rep[i] = repToConfirm[i];
|
||||
|
||||
/* Fill tables for block compressor */
|
||||
ZSTD_ldm_limitTableUpdate(cctx, anchor);
|
||||
ZSTD_ldm_fillFastTables(cctx, anchor);
|
||||
|
||||
/* Call block compressor and get remaining literals */
|
||||
lastLiterals = blockCompressor(cctx, anchor, ip - anchor);
|
||||
cctx->nextToUpdate = (U32)(ip - base);
|
||||
|
||||
/* Update repToConfirm with the new offset */
|
||||
for (i = ZSTD_REP_NUM - 1; i > 0; i--)
|
||||
repToConfirm[i] = repToConfirm[i-1];
|
||||
repToConfirm[0] = offset;
|
||||
|
||||
/* Store the sequence with the leftover literals */
|
||||
ZSTD_storeSeq(seqStorePtr, lastLiterals, ip - lastLiterals,
|
||||
offset + ZSTD_REP_MOVE, mLength - MINMATCH);
|
||||
}
|
||||
|
||||
/* Insert the current entry into the hash table */
|
||||
ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
|
||||
(U32)(lastHashed - base),
|
||||
ldmParams);
|
||||
|
||||
assert(ip + backwardMatchLength == lastHashed);
|
||||
|
||||
/* Fill the hash table from lastHashed+1 to ip+mLength*/
|
||||
/* Heuristic: don't need to fill the entire table at end of block */
|
||||
if (ip + mLength < ilimit) {
|
||||
rollingHash = ZSTD_ldm_fillLdmHashTable(
|
||||
ldmState, rollingHash, lastHashed,
|
||||
ip + mLength, base, hBits, ldmParams);
|
||||
lastHashed = ip + mLength - 1;
|
||||
}
|
||||
ip += mLength;
|
||||
anchor = ip;
|
||||
/* Check immediate repcode */
|
||||
while ( (ip < ilimit)
|
||||
&& ( (repToConfirm[1] > 0) && (repToConfirm[1] <= (U32)(ip-lowest))
|
||||
&& (MEM_read32(ip) == MEM_read32(ip - repToConfirm[1])) )) {
|
||||
|
||||
size_t const rLength = ZSTD_count(ip+4, ip+4-repToConfirm[1],
|
||||
iend) + 4;
|
||||
/* Swap repToConfirm[1] <=> repToConfirm[0] */
|
||||
{
|
||||
U32 const tmpOff = repToConfirm[1];
|
||||
repToConfirm[1] = repToConfirm[0];
|
||||
repToConfirm[0] = tmpOff;
|
||||
}
|
||||
|
||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
|
||||
|
||||
/* Fill the hash table from lastHashed+1 to ip+rLength*/
|
||||
if (ip + rLength < ilimit) {
|
||||
rollingHash = ZSTD_ldm_fillLdmHashTable(
|
||||
ldmState, rollingHash, lastHashed,
|
||||
ip + rLength, base, hBits, ldmParams);
|
||||
lastHashed = ip + rLength - 1;
|
||||
}
|
||||
ip += rLength;
|
||||
anchor = ip;
|
||||
}
|
||||
}
|
||||
|
||||
/* Overwrite rep */
|
||||
for (i = 0; i < ZSTD_REP_NUM; i++)
|
||||
seqStorePtr->rep[i] = repToConfirm[i];
|
||||
|
||||
ZSTD_ldm_limitTableUpdate(cctx, anchor);
|
||||
ZSTD_ldm_fillFastTables(cctx, anchor);
|
||||
|
||||
lastLiterals = blockCompressor(cctx, anchor, iend - anchor);
|
||||
cctx->nextToUpdate = (U32)(iend - base);
|
||||
|
||||
/* Restore seqStorePtr->rep */
|
||||
for (i = 0; i < ZSTD_REP_NUM; i++)
|
||||
seqStorePtr->rep[i] = savedRep[i];
|
||||
|
||||
/* Return the last literals size */
|
||||
return lastLiterals;
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_ldm(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_ldm_generic(ctx, src, srcSize);
|
||||
}
|
||||
|
||||
static size_t ZSTD_compressBlock_ldm_extDict_generic(
|
||||
ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
ldmState_t* const ldmState = &(ctx->ldmState);
|
||||
const ldmParams_t ldmParams = ctx->appliedParams.ldmParams;
|
||||
const U64 hashPower = ldmState->hashPower;
|
||||
const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog;
|
||||
const U32 ldmBucketSize = ((U32)1 << ldmParams.bucketSizeLog);
|
||||
const U32 ldmTagMask = ((U32)1 << ldmParams.hashEveryLog) - 1;
|
||||
seqStore_t* const seqStorePtr = &(ctx->seqStore);
|
||||
const BYTE* const base = ctx->base;
|
||||
const BYTE* const dictBase = ctx->dictBase;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 lowestIndex = ctx->lowLimit;
|
||||
const BYTE* const dictStart = dictBase + lowestIndex;
|
||||
const U32 dictLimit = ctx->dictLimit;
|
||||
const BYTE* const lowPrefixPtr = base + dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - ldmParams.minMatchLength;
|
||||
|
||||
const ZSTD_blockCompressor blockCompressor =
|
||||
ZSTD_selectBlockCompressor(ctx->appliedParams.cParams.strategy, 1);
|
||||
U32* const repToConfirm = seqStorePtr->repToConfirm;
|
||||
U32 savedRep[ZSTD_REP_NUM];
|
||||
U64 rollingHash = 0;
|
||||
const BYTE* lastHashed = NULL;
|
||||
size_t i, lastLiterals;
|
||||
|
||||
/* Save seqStorePtr->rep and copy repToConfirm */
|
||||
for (i = 0; i < ZSTD_REP_NUM; i++) {
|
||||
savedRep[i] = repToConfirm[i] = seqStorePtr->rep[i];
|
||||
}
|
||||
|
||||
/* Search Loop */
|
||||
while (ip < ilimit) { /* < instead of <=, because (ip+1) */
|
||||
size_t mLength;
|
||||
const U32 current = (U32)(ip-base);
|
||||
size_t forwardMatchLength = 0, backwardMatchLength = 0;
|
||||
ldmEntry_t* bestEntry = NULL;
|
||||
if (ip != istart) {
|
||||
rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0],
|
||||
lastHashed[ldmParams.minMatchLength],
|
||||
hashPower);
|
||||
} else {
|
||||
rollingHash = ZSTD_ldm_getRollingHash(ip, ldmParams.minMatchLength);
|
||||
}
|
||||
lastHashed = ip;
|
||||
|
||||
if (ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog) !=
|
||||
ldmTagMask) {
|
||||
/* Don't insert and don't look for a match */
|
||||
ip++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get the best entry and compute the match lengths */
|
||||
{
|
||||
ldmEntry_t* const bucket =
|
||||
ZSTD_ldm_getBucket(ldmState,
|
||||
ZSTD_ldm_getSmallHash(rollingHash, hBits),
|
||||
ldmParams);
|
||||
ldmEntry_t* cur;
|
||||
size_t bestMatchLength = 0;
|
||||
U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
|
||||
|
||||
for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) {
|
||||
const BYTE* const curMatchBase =
|
||||
cur->offset < dictLimit ? dictBase : base;
|
||||
const BYTE* const pMatch = curMatchBase + cur->offset;
|
||||
const BYTE* const matchEnd =
|
||||
cur->offset < dictLimit ? dictEnd : iend;
|
||||
const BYTE* const lowMatchPtr =
|
||||
cur->offset < dictLimit ? dictStart : lowPrefixPtr;
|
||||
size_t curForwardMatchLength, curBackwardMatchLength,
|
||||
curTotalMatchLength;
|
||||
|
||||
if (cur->checksum != checksum || cur->offset <= lowestIndex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
curForwardMatchLength = ZSTD_count_2segments(
|
||||
ip, pMatch, iend,
|
||||
matchEnd, lowPrefixPtr);
|
||||
if (curForwardMatchLength < ldmParams.minMatchLength) {
|
||||
continue;
|
||||
}
|
||||
curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch(
|
||||
ip, anchor, pMatch, lowMatchPtr);
|
||||
curTotalMatchLength = curForwardMatchLength +
|
||||
curBackwardMatchLength;
|
||||
|
||||
if (curTotalMatchLength > bestMatchLength) {
|
||||
bestMatchLength = curTotalMatchLength;
|
||||
forwardMatchLength = curForwardMatchLength;
|
||||
backwardMatchLength = curBackwardMatchLength;
|
||||
bestEntry = cur;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* No match found -- continue searching */
|
||||
if (bestEntry == NULL) {
|
||||
ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
|
||||
(U32)(lastHashed - base),
|
||||
ldmParams);
|
||||
ip++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Match found */
|
||||
mLength = forwardMatchLength + backwardMatchLength;
|
||||
ip -= backwardMatchLength;
|
||||
|
||||
/* Call the block compressor on the remaining literals */
|
||||
{
|
||||
/* ip = current - backwardMatchLength
|
||||
* The match is at (bestEntry->offset - backwardMatchLength) */
|
||||
U32 const matchIndex = bestEntry->offset;
|
||||
U32 const offset = current - matchIndex;
|
||||
|
||||
/* Overwrite rep codes */
|
||||
for (i = 0; i < ZSTD_REP_NUM; i++)
|
||||
seqStorePtr->rep[i] = repToConfirm[i];
|
||||
|
||||
/* Fill the hash table for the block compressor */
|
||||
ZSTD_ldm_limitTableUpdate(ctx, anchor);
|
||||
ZSTD_ldm_fillFastTables(ctx, anchor);
|
||||
|
||||
/* Call block compressor and get remaining literals */
|
||||
lastLiterals = blockCompressor(ctx, anchor, ip - anchor);
|
||||
ctx->nextToUpdate = (U32)(ip - base);
|
||||
|
||||
/* Update repToConfirm with the new offset */
|
||||
for (i = ZSTD_REP_NUM - 1; i > 0; i--)
|
||||
repToConfirm[i] = repToConfirm[i-1];
|
||||
repToConfirm[0] = offset;
|
||||
|
||||
/* Store the sequence with the leftover literals */
|
||||
ZSTD_storeSeq(seqStorePtr, lastLiterals, ip - lastLiterals,
|
||||
offset + ZSTD_REP_MOVE, mLength - MINMATCH);
|
||||
}
|
||||
|
||||
/* Insert the current entry into the hash table */
|
||||
ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
|
||||
(U32)(lastHashed - base),
|
||||
ldmParams);
|
||||
|
||||
/* Fill the hash table from lastHashed+1 to ip+mLength */
|
||||
assert(ip + backwardMatchLength == lastHashed);
|
||||
if (ip + mLength < ilimit) {
|
||||
rollingHash = ZSTD_ldm_fillLdmHashTable(
|
||||
ldmState, rollingHash, lastHashed,
|
||||
ip + mLength, base, hBits,
|
||||
ldmParams);
|
||||
lastHashed = ip + mLength - 1;
|
||||
}
|
||||
ip += mLength;
|
||||
anchor = ip;
|
||||
|
||||
/* check immediate repcode */
|
||||
while (ip < ilimit) {
|
||||
U32 const current2 = (U32)(ip-base);
|
||||
U32 const repIndex2 = current2 - repToConfirm[1];
|
||||
const BYTE* repMatch2 = repIndex2 < dictLimit ?
|
||||
dictBase + repIndex2 : base + repIndex2;
|
||||
if ( (((U32)((dictLimit-1) - repIndex2) >= 3) &
|
||||
(repIndex2 > lowestIndex)) /* intentional overflow */
|
||||
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
||||
const BYTE* const repEnd2 = repIndex2 < dictLimit ?
|
||||
dictEnd : iend;
|
||||
size_t const repLength2 =
|
||||
ZSTD_count_2segments(ip+4, repMatch2+4, iend,
|
||||
repEnd2, lowPrefixPtr) + 4;
|
||||
|
||||
U32 tmpOffset = repToConfirm[1];
|
||||
repToConfirm[1] = repToConfirm[0];
|
||||
repToConfirm[0] = tmpOffset;
|
||||
|
||||
ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
|
||||
|
||||
/* Fill the hash table from lastHashed+1 to ip+repLength2*/
|
||||
if (ip + repLength2 < ilimit) {
|
||||
rollingHash = ZSTD_ldm_fillLdmHashTable(
|
||||
ldmState, rollingHash, lastHashed,
|
||||
ip + repLength2, base, hBits,
|
||||
ldmParams);
|
||||
lastHashed = ip + repLength2 - 1;
|
||||
}
|
||||
ip += repLength2;
|
||||
anchor = ip;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Overwrite rep */
|
||||
for (i = 0; i < ZSTD_REP_NUM; i++)
|
||||
seqStorePtr->rep[i] = repToConfirm[i];
|
||||
|
||||
ZSTD_ldm_limitTableUpdate(ctx, anchor);
|
||||
ZSTD_ldm_fillFastTables(ctx, anchor);
|
||||
|
||||
/* Call the block compressor one last time on the last literals */
|
||||
lastLiterals = blockCompressor(ctx, anchor, iend - anchor);
|
||||
ctx->nextToUpdate = (U32)(iend - base);
|
||||
|
||||
/* Restore seqStorePtr->rep */
|
||||
for (i = 0; i < ZSTD_REP_NUM; i++)
|
||||
seqStorePtr->rep[i] = savedRep[i];
|
||||
|
||||
/* Return the last literals size */
|
||||
return lastLiterals;
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_ldm_extDict(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_ldm_extDict_generic(ctx, src, srcSize);
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_LDM_H
|
||||
#define ZSTD_LDM_H
|
||||
|
||||
#include "zstd_compress.h"
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*-*************************************
|
||||
* Long distance matching
|
||||
***************************************/
|
||||
|
||||
#define ZSTD_LDM_WINDOW_LOG 27
|
||||
#define ZSTD_LDM_HASHEVERYLOG_NOTSET 9999
|
||||
|
||||
/** ZSTD_compressBlock_ldm_generic() :
|
||||
*
|
||||
* This is a block compressor intended for long distance matching.
|
||||
*
|
||||
* The function searches for matches of length at least
|
||||
* ldmParams.minMatchLength using a hash table in cctx->ldmState.
|
||||
* Matches can be at a distance of up to cParams.windowLog.
|
||||
*
|
||||
* Upon finding a match, the unmatched literals are compressed using a
|
||||
* ZSTD_blockCompressor (depending on the strategy in the compression
|
||||
* parameters), which stores the matched sequences. The "long distance"
|
||||
* match is then stored with the remaining literals from the
|
||||
* ZSTD_blockCompressor. */
|
||||
size_t ZSTD_compressBlock_ldm(ZSTD_CCtx* cctx, const void* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_ldm_extDict(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize);
|
||||
|
||||
/** ZSTD_ldm_initializeParameters() :
|
||||
* Initialize the long distance matching parameters to their default values. */
|
||||
size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm);
|
||||
|
||||
/** ZSTD_ldm_getTableSize() :
|
||||
* Estimate the space needed for long distance matching tables. */
|
||||
size_t ZSTD_ldm_getTableSize(U32 hashLog, U32 bucketSizeLog);
|
||||
|
||||
/** ZSTD_ldm_getTableSize() :
|
||||
* Return prime8bytes^(minMatchLength-1) */
|
||||
U64 ZSTD_ldm_getHashPower(U32 minMatchLength);
|
||||
|
||||
/** ZSTD_ldm_adjustParameters() :
|
||||
* If the params->hashEveryLog is not set, set it to its default value based on
|
||||
* windowLog and params->hashLog.
|
||||
*
|
||||
* Ensures that params->bucketSizeLog is <= params->hashLog (setting it to
|
||||
* params->hashLog if it is not). */
|
||||
void ZSTD_ldm_adjustParameters(ldmParams_t* params, U32 windowLog);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZSTD_FAST_H */
|
||||
@@ -1,949 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#include "zstd_opt.h"
|
||||
#include "zstd_lazy.h"
|
||||
|
||||
|
||||
#define ZSTD_LITFREQ_ADD 2
|
||||
#define ZSTD_FREQ_DIV 4
|
||||
#define ZSTD_MAX_PRICE (1<<30)
|
||||
|
||||
/*-*************************************
|
||||
* Price functions for optimal parser
|
||||
***************************************/
|
||||
static void ZSTD_setLog2Prices(optState_t* optPtr)
|
||||
{
|
||||
optPtr->log2matchLengthSum = ZSTD_highbit32(optPtr->matchLengthSum+1);
|
||||
optPtr->log2litLengthSum = ZSTD_highbit32(optPtr->litLengthSum+1);
|
||||
optPtr->log2litSum = ZSTD_highbit32(optPtr->litSum+1);
|
||||
optPtr->log2offCodeSum = ZSTD_highbit32(optPtr->offCodeSum+1);
|
||||
optPtr->factor = 1 + ((optPtr->litSum>>5) / optPtr->litLengthSum) + ((optPtr->litSum<<1) / (optPtr->litSum + optPtr->matchSum));
|
||||
}
|
||||
|
||||
|
||||
static void ZSTD_rescaleFreqs(optState_t* optPtr, const BYTE* src, size_t srcSize)
|
||||
{
|
||||
unsigned u;
|
||||
|
||||
optPtr->cachedLiterals = NULL;
|
||||
optPtr->cachedPrice = optPtr->cachedLitLength = 0;
|
||||
optPtr->staticPrices = 0;
|
||||
|
||||
if (optPtr->litLengthSum == 0) {
|
||||
if (srcSize <= 1024) optPtr->staticPrices = 1;
|
||||
|
||||
assert(optPtr->litFreq!=NULL);
|
||||
for (u=0; u<=MaxLit; u++)
|
||||
optPtr->litFreq[u] = 0;
|
||||
for (u=0; u<srcSize; u++)
|
||||
optPtr->litFreq[src[u]]++;
|
||||
|
||||
optPtr->litSum = 0;
|
||||
optPtr->litLengthSum = MaxLL+1;
|
||||
optPtr->matchLengthSum = MaxML+1;
|
||||
optPtr->offCodeSum = (MaxOff+1);
|
||||
optPtr->matchSum = (ZSTD_LITFREQ_ADD<<Litbits);
|
||||
|
||||
for (u=0; u<=MaxLit; u++) {
|
||||
optPtr->litFreq[u] = 1 + (optPtr->litFreq[u]>>ZSTD_FREQ_DIV);
|
||||
optPtr->litSum += optPtr->litFreq[u];
|
||||
}
|
||||
for (u=0; u<=MaxLL; u++)
|
||||
optPtr->litLengthFreq[u] = 1;
|
||||
for (u=0; u<=MaxML; u++)
|
||||
optPtr->matchLengthFreq[u] = 1;
|
||||
for (u=0; u<=MaxOff; u++)
|
||||
optPtr->offCodeFreq[u] = 1;
|
||||
} else {
|
||||
optPtr->matchLengthSum = 0;
|
||||
optPtr->litLengthSum = 0;
|
||||
optPtr->offCodeSum = 0;
|
||||
optPtr->matchSum = 0;
|
||||
optPtr->litSum = 0;
|
||||
|
||||
for (u=0; u<=MaxLit; u++) {
|
||||
optPtr->litFreq[u] = 1 + (optPtr->litFreq[u]>>(ZSTD_FREQ_DIV+1));
|
||||
optPtr->litSum += optPtr->litFreq[u];
|
||||
}
|
||||
for (u=0; u<=MaxLL; u++) {
|
||||
optPtr->litLengthFreq[u] = 1 + (optPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1));
|
||||
optPtr->litLengthSum += optPtr->litLengthFreq[u];
|
||||
}
|
||||
for (u=0; u<=MaxML; u++) {
|
||||
optPtr->matchLengthFreq[u] = 1 + (optPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV);
|
||||
optPtr->matchLengthSum += optPtr->matchLengthFreq[u];
|
||||
optPtr->matchSum += optPtr->matchLengthFreq[u] * (u + 3);
|
||||
}
|
||||
optPtr->matchSum *= ZSTD_LITFREQ_ADD;
|
||||
for (u=0; u<=MaxOff; u++) {
|
||||
optPtr->offCodeFreq[u] = 1 + (optPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV);
|
||||
optPtr->offCodeSum += optPtr->offCodeFreq[u];
|
||||
}
|
||||
}
|
||||
|
||||
ZSTD_setLog2Prices(optPtr);
|
||||
}
|
||||
|
||||
|
||||
static U32 ZSTD_getLiteralPrice(optState_t* optPtr, U32 litLength, const BYTE* literals)
|
||||
{
|
||||
U32 price, u;
|
||||
|
||||
if (optPtr->staticPrices)
|
||||
return ZSTD_highbit32((U32)litLength+1) + (litLength*6);
|
||||
|
||||
if (litLength == 0)
|
||||
return optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[0]+1);
|
||||
|
||||
/* literals */
|
||||
if (optPtr->cachedLiterals == literals) {
|
||||
U32 const additional = litLength - optPtr->cachedLitLength;
|
||||
const BYTE* literals2 = optPtr->cachedLiterals + optPtr->cachedLitLength;
|
||||
price = optPtr->cachedPrice + additional * optPtr->log2litSum;
|
||||
for (u=0; u < additional; u++)
|
||||
price -= ZSTD_highbit32(optPtr->litFreq[literals2[u]]+1);
|
||||
optPtr->cachedPrice = price;
|
||||
optPtr->cachedLitLength = litLength;
|
||||
} else {
|
||||
price = litLength * optPtr->log2litSum;
|
||||
for (u=0; u < litLength; u++)
|
||||
price -= ZSTD_highbit32(optPtr->litFreq[literals[u]]+1);
|
||||
|
||||
if (litLength >= 12) {
|
||||
optPtr->cachedLiterals = literals;
|
||||
optPtr->cachedPrice = price;
|
||||
optPtr->cachedLitLength = litLength;
|
||||
}
|
||||
}
|
||||
|
||||
/* literal Length */
|
||||
{ const BYTE LL_deltaCode = 19;
|
||||
const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
|
||||
price += LL_bits[llCode] + optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1);
|
||||
}
|
||||
|
||||
return price;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE U32 ZSTD_getPrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength, const int ultra)
|
||||
{
|
||||
/* offset */
|
||||
U32 price;
|
||||
BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
|
||||
|
||||
if (optPtr->staticPrices)
|
||||
return ZSTD_getLiteralPrice(optPtr, litLength, literals) + ZSTD_highbit32((U32)matchLength+1) + 16 + offCode;
|
||||
|
||||
price = offCode + optPtr->log2offCodeSum - ZSTD_highbit32(optPtr->offCodeFreq[offCode]+1);
|
||||
if (!ultra && offCode >= 20) price += (offCode-19)*2;
|
||||
|
||||
/* match Length */
|
||||
{ const BYTE ML_deltaCode = 36;
|
||||
const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
|
||||
price += ML_bits[mlCode] + optPtr->log2matchLengthSum - ZSTD_highbit32(optPtr->matchLengthFreq[mlCode]+1);
|
||||
}
|
||||
|
||||
return price + ZSTD_getLiteralPrice(optPtr, litLength, literals) + optPtr->factor;
|
||||
}
|
||||
|
||||
|
||||
static void ZSTD_updatePrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength)
|
||||
{
|
||||
U32 u;
|
||||
|
||||
/* literals */
|
||||
optPtr->litSum += litLength*ZSTD_LITFREQ_ADD;
|
||||
for (u=0; u < litLength; u++)
|
||||
optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
|
||||
|
||||
/* literal Length */
|
||||
{ const BYTE LL_deltaCode = 19;
|
||||
const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
|
||||
optPtr->litLengthFreq[llCode]++;
|
||||
optPtr->litLengthSum++;
|
||||
}
|
||||
|
||||
/* match offset */
|
||||
{ BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
|
||||
optPtr->offCodeSum++;
|
||||
optPtr->offCodeFreq[offCode]++;
|
||||
}
|
||||
|
||||
/* match Length */
|
||||
{ const BYTE ML_deltaCode = 36;
|
||||
const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
|
||||
optPtr->matchLengthFreq[mlCode]++;
|
||||
optPtr->matchLengthSum++;
|
||||
}
|
||||
|
||||
ZSTD_setLog2Prices(optPtr);
|
||||
}
|
||||
|
||||
|
||||
#define SET_PRICE(pos, mlen_, offset_, litlen_, price_) \
|
||||
{ \
|
||||
while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } \
|
||||
opt[pos].mlen = mlen_; \
|
||||
opt[pos].off = offset_; \
|
||||
opt[pos].litlen = litlen_; \
|
||||
opt[pos].price = price_; \
|
||||
}
|
||||
|
||||
|
||||
/* function safe only for comparisons */
|
||||
static U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
|
||||
{
|
||||
switch (length)
|
||||
{
|
||||
default :
|
||||
case 4 : return MEM_read32(memPtr);
|
||||
case 3 : if (MEM_isLittleEndian())
|
||||
return MEM_read32(memPtr)<<8;
|
||||
else
|
||||
return MEM_read32(memPtr)>>8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Update hashTable3 up to ip (excluded)
|
||||
Assumption : always within prefix (i.e. not within extDict) */
|
||||
static
|
||||
U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* zc, const BYTE* ip)
|
||||
{
|
||||
U32* const hashTable3 = zc->hashTable3;
|
||||
U32 const hashLog3 = zc->hashLog3;
|
||||
const BYTE* const base = zc->base;
|
||||
U32 idx = zc->nextToUpdate3;
|
||||
const U32 target = zc->nextToUpdate3 = (U32)(ip - base);
|
||||
const size_t hash3 = ZSTD_hash3Ptr(ip, hashLog3);
|
||||
|
||||
while(idx < target) {
|
||||
hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
|
||||
idx++;
|
||||
}
|
||||
|
||||
return hashTable3[hash3];
|
||||
}
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Binary Tree search
|
||||
***************************************/
|
||||
static U32 ZSTD_insertBtAndGetAllMatches (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
U32 nbCompares, const U32 mls,
|
||||
U32 extDict, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||
{
|
||||
const BYTE* const base = zc->base;
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 hashLog = zc->appliedParams.cParams.hashLog;
|
||||
const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
|
||||
U32* const hashTable = zc->hashTable;
|
||||
U32 matchIndex = hashTable[h];
|
||||
U32* const bt = zc->chainTable;
|
||||
const U32 btLog = zc->appliedParams.cParams.chainLog - 1;
|
||||
const U32 btMask= (1U << btLog) - 1;
|
||||
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
||||
const BYTE* const dictBase = zc->dictBase;
|
||||
const U32 dictLimit = zc->dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const prefixStart = base + dictLimit;
|
||||
const U32 btLow = btMask >= current ? 0 : current - btMask;
|
||||
const U32 windowLow = zc->lowLimit;
|
||||
U32* smallerPtr = bt + 2*(current&btMask);
|
||||
U32* largerPtr = bt + 2*(current&btMask) + 1;
|
||||
U32 matchEndIdx = current+8;
|
||||
U32 dummy32; /* to be nullified at the end */
|
||||
U32 mnum = 0;
|
||||
|
||||
const U32 minMatch = (mls == 3) ? 3 : 4;
|
||||
size_t bestLength = minMatchLen-1;
|
||||
|
||||
if (minMatch == 3) { /* HC3 match finder */
|
||||
U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip);
|
||||
if (matchIndex3>windowLow && (current - matchIndex3 < (1<<18))) {
|
||||
const BYTE* match;
|
||||
size_t currentMl=0;
|
||||
if ((!extDict) || matchIndex3 >= dictLimit) {
|
||||
match = base + matchIndex3;
|
||||
if (match[bestLength] == ip[bestLength]) currentMl = ZSTD_count(ip, match, iLimit);
|
||||
} else {
|
||||
match = dictBase + matchIndex3;
|
||||
if (ZSTD_readMINMATCH(match, MINMATCH) == ZSTD_readMINMATCH(ip, MINMATCH)) /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */
|
||||
currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
|
||||
}
|
||||
|
||||
/* save best solution */
|
||||
if (currentMl > bestLength) {
|
||||
bestLength = currentMl;
|
||||
matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex3;
|
||||
matches[mnum].len = (U32)currentMl;
|
||||
mnum++;
|
||||
if (currentMl > ZSTD_OPT_NUM) goto update;
|
||||
if (ip+currentMl == iLimit) goto update; /* best possible, and avoid read overflow*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hashTable[h] = current; /* Update Hash Table */
|
||||
|
||||
while (nbCompares-- && (matchIndex > windowLow)) {
|
||||
U32* nextPtr = bt + 2*(matchIndex & btMask);
|
||||
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||
const BYTE* match;
|
||||
|
||||
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
|
||||
match = base + matchIndex;
|
||||
if (match[matchLength] == ip[matchLength]) {
|
||||
matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iLimit) +1;
|
||||
}
|
||||
} else {
|
||||
match = dictBase + matchIndex;
|
||||
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
|
||||
if (matchIndex+matchLength >= dictLimit)
|
||||
match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
|
||||
}
|
||||
|
||||
if (matchLength > bestLength) {
|
||||
if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength;
|
||||
bestLength = matchLength;
|
||||
matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex;
|
||||
matches[mnum].len = (U32)matchLength;
|
||||
mnum++;
|
||||
if (matchLength > ZSTD_OPT_NUM) break;
|
||||
if (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */
|
||||
break; /* drop, to guarantee consistency (miss a little bit of compression) */
|
||||
}
|
||||
|
||||
if (match[matchLength] < ip[matchLength]) {
|
||||
/* match is smaller than current */
|
||||
*smallerPtr = matchIndex; /* update smaller idx */
|
||||
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
|
||||
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||
smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
|
||||
matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
|
||||
} else {
|
||||
/* match is larger than current */
|
||||
*largerPtr = matchIndex;
|
||||
commonLengthLarger = matchLength;
|
||||
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||
largerPtr = nextPtr;
|
||||
matchIndex = nextPtr[0];
|
||||
} }
|
||||
|
||||
*smallerPtr = *largerPtr = 0;
|
||||
|
||||
update:
|
||||
zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
|
||||
return mnum;
|
||||
}
|
||||
|
||||
|
||||
/** Tree updater, providing best match */
|
||||
static U32 ZSTD_BtGetAllMatches (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||
{
|
||||
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
|
||||
ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
|
||||
return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches, minMatchLen);
|
||||
}
|
||||
|
||||
|
||||
static U32 ZSTD_BtGetAllMatches_selectMLS (
|
||||
ZSTD_CCtx* zc, /* Index table will be updated */
|
||||
const BYTE* ip, const BYTE* const iHighLimit,
|
||||
const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||
{
|
||||
switch(matchLengthSearch)
|
||||
{
|
||||
case 3 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
|
||||
default :
|
||||
case 4 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
|
||||
case 5 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
|
||||
}
|
||||
}
|
||||
|
||||
/** Tree updater, providing best match */
|
||||
static U32 ZSTD_BtGetAllMatches_extDict (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||
{
|
||||
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
|
||||
ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
|
||||
return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minMatchLen);
|
||||
}
|
||||
|
||||
|
||||
static U32 ZSTD_BtGetAllMatches_selectMLS_extDict (
|
||||
ZSTD_CCtx* zc, /* Index table will be updated */
|
||||
const BYTE* ip, const BYTE* const iHighLimit,
|
||||
const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||
{
|
||||
switch(matchLengthSearch)
|
||||
{
|
||||
case 3 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
|
||||
default :
|
||||
case 4 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
|
||||
case 5 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-*******************************
|
||||
* Optimal parser
|
||||
*********************************/
|
||||
FORCE_INLINE_TEMPLATE
|
||||
size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize, const int ultra)
|
||||
{
|
||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
||||
optState_t* optStatePtr = &(ctx->optState);
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
const BYTE* const base = ctx->base;
|
||||
const BYTE* const prefixStart = base + ctx->dictLimit;
|
||||
|
||||
const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
|
||||
const U32 sufficient_len = ctx->appliedParams.cParams.targetLength;
|
||||
const U32 mls = ctx->appliedParams.cParams.searchLength;
|
||||
const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
|
||||
|
||||
ZSTD_optimal_t* opt = optStatePtr->priceTable;
|
||||
ZSTD_match_t* matches = optStatePtr->matchTable;
|
||||
const BYTE* inr;
|
||||
U32 offset, rep[ZSTD_REP_NUM];
|
||||
|
||||
/* init */
|
||||
ctx->nextToUpdate3 = ctx->nextToUpdate;
|
||||
ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
|
||||
ip += (ip==prefixStart);
|
||||
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; }
|
||||
|
||||
/* Match Loop */
|
||||
while (ip < ilimit) {
|
||||
U32 cur, match_num, last_pos, litlen, price;
|
||||
U32 u, mlen, best_mlen, best_off, litLength;
|
||||
memset(opt, 0, sizeof(ZSTD_optimal_t));
|
||||
last_pos = 0;
|
||||
litlen = (U32)(ip - anchor);
|
||||
|
||||
/* check repCode */
|
||||
{ U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
|
||||
for (i=(ip == anchor); i<last_i; i++) {
|
||||
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i];
|
||||
if ( (repCur > 0) && (repCur < (S32)(ip-prefixStart))
|
||||
&& (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repCur, minMatch))) {
|
||||
mlen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repCur, iend) + minMatch;
|
||||
if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
|
||||
best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
best_off = i - (ip == anchor);
|
||||
do {
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
|
||||
if (mlen > last_pos || price < opt[mlen].price)
|
||||
SET_PRICE(mlen, mlen, i, litlen, price); /* note : macro modifies last_pos */
|
||||
mlen--;
|
||||
} while (mlen >= minMatch);
|
||||
} } }
|
||||
|
||||
match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, ip, iend, maxSearches, mls, matches, minMatch);
|
||||
|
||||
if (!last_pos && !match_num) { ip++; continue; }
|
||||
|
||||
if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
|
||||
best_mlen = matches[match_num-1].len;
|
||||
best_off = matches[match_num-1].off;
|
||||
cur = 0;
|
||||
last_pos = 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
|
||||
/* set prices using matches at position = 0 */
|
||||
best_mlen = (last_pos) ? last_pos : minMatch;
|
||||
for (u = 0; u < match_num; u++) {
|
||||
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
|
||||
best_mlen = matches[u].len;
|
||||
while (mlen <= best_mlen) {
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
if (mlen > last_pos || price < opt[mlen].price)
|
||||
SET_PRICE(mlen, mlen, matches[u].off, litlen, price); /* note : macro modifies last_pos */
|
||||
mlen++;
|
||||
} }
|
||||
|
||||
if (last_pos < minMatch) { ip++; continue; }
|
||||
|
||||
/* initialize opt[0] */
|
||||
{ U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
|
||||
opt[0].mlen = 1;
|
||||
opt[0].litlen = litlen;
|
||||
|
||||
/* check further positions */
|
||||
for (cur = 1; cur <= last_pos; cur++) {
|
||||
inr = ip + cur;
|
||||
|
||||
if (opt[cur-1].mlen == 1) {
|
||||
litlen = opt[cur-1].litlen + 1;
|
||||
if (cur > litlen) {
|
||||
price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen);
|
||||
} else
|
||||
price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor);
|
||||
} else {
|
||||
litlen = 1;
|
||||
price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1);
|
||||
}
|
||||
|
||||
if (cur > last_pos || price <= opt[cur].price)
|
||||
SET_PRICE(cur, 1, 0, litlen, price);
|
||||
|
||||
if (cur == last_pos) break;
|
||||
|
||||
if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */
|
||||
continue;
|
||||
|
||||
mlen = opt[cur].mlen;
|
||||
if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
|
||||
opt[cur].rep[2] = opt[cur-mlen].rep[1];
|
||||
opt[cur].rep[1] = opt[cur-mlen].rep[0];
|
||||
opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
|
||||
} 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]);
|
||||
}
|
||||
|
||||
best_mlen = minMatch;
|
||||
{ U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
|
||||
for (i=(opt[cur].mlen != 1); i<last_i; i++) { /* check rep */
|
||||
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i];
|
||||
if ( (repCur > 0) && (repCur < (S32)(inr-prefixStart))
|
||||
&& (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(inr - repCur, minMatch))) {
|
||||
mlen = (U32)ZSTD_count(inr+minMatch, inr+minMatch - repCur, iend) + minMatch;
|
||||
|
||||
if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
|
||||
best_mlen = mlen; best_off = i; last_pos = cur + 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
|
||||
best_off = i - (opt[cur].mlen != 1);
|
||||
if (mlen > best_mlen) best_mlen = mlen;
|
||||
|
||||
do {
|
||||
if (opt[cur].mlen == 1) {
|
||||
litlen = opt[cur].litlen;
|
||||
if (cur > litlen) {
|
||||
price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
|
||||
} else
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
|
||||
} else {
|
||||
litlen = 0;
|
||||
price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
|
||||
}
|
||||
|
||||
if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
|
||||
SET_PRICE(cur + mlen, mlen, i, litlen, price);
|
||||
mlen--;
|
||||
} while (mlen >= minMatch);
|
||||
} } }
|
||||
|
||||
match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, inr, iend, maxSearches, mls, matches, best_mlen);
|
||||
|
||||
if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
|
||||
best_mlen = matches[match_num-1].len;
|
||||
best_off = matches[match_num-1].off;
|
||||
last_pos = cur + 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
|
||||
/* set prices using matches at position = cur */
|
||||
for (u = 0; u < match_num; u++) {
|
||||
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
|
||||
best_mlen = matches[u].len;
|
||||
|
||||
while (mlen <= best_mlen) {
|
||||
if (opt[cur].mlen == 1) {
|
||||
litlen = opt[cur].litlen;
|
||||
if (cur > litlen)
|
||||
price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
else
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
} else {
|
||||
litlen = 0;
|
||||
price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
}
|
||||
|
||||
if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
|
||||
SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
|
||||
|
||||
mlen++;
|
||||
} } }
|
||||
|
||||
best_mlen = opt[last_pos].mlen;
|
||||
best_off = opt[last_pos].off;
|
||||
cur = last_pos - best_mlen;
|
||||
|
||||
/* store sequence */
|
||||
_storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
|
||||
opt[0].mlen = 1;
|
||||
|
||||
while (1) {
|
||||
mlen = opt[cur].mlen;
|
||||
offset = opt[cur].off;
|
||||
opt[cur].mlen = best_mlen;
|
||||
opt[cur].off = best_off;
|
||||
best_mlen = mlen;
|
||||
best_off = offset;
|
||||
if (mlen > cur) break;
|
||||
cur -= mlen;
|
||||
}
|
||||
|
||||
for (u = 0; u <= last_pos;) {
|
||||
u += opt[u].mlen;
|
||||
}
|
||||
|
||||
for (cur=0; cur < last_pos; ) {
|
||||
mlen = opt[cur].mlen;
|
||||
if (mlen == 1) { ip++; cur++; continue; }
|
||||
offset = opt[cur].off;
|
||||
cur += mlen;
|
||||
litLength = (U32)(ip - anchor);
|
||||
|
||||
if (offset > ZSTD_REP_MOVE_OPT) {
|
||||
rep[2] = rep[1];
|
||||
rep[1] = rep[0];
|
||||
rep[0] = offset - ZSTD_REP_MOVE_OPT;
|
||||
offset--;
|
||||
} else {
|
||||
if (offset != 0) {
|
||||
best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
|
||||
if (offset != 1) rep[2] = rep[1];
|
||||
rep[1] = rep[0];
|
||||
rep[0] = best_off;
|
||||
}
|
||||
if (litLength==0) offset--;
|
||||
}
|
||||
|
||||
ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH);
|
||||
ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
|
||||
anchor = ip = ip + mlen;
|
||||
} } /* for (cur=0; cur < last_pos; ) */
|
||||
|
||||
/* Save reps for next block */
|
||||
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; }
|
||||
|
||||
/* Return the last literals size */
|
||||
return iend - anchor;
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
size_t ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize, const int ultra)
|
||||
{
|
||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
||||
optState_t* optStatePtr = &(ctx->optState);
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
const BYTE* const base = ctx->base;
|
||||
const U32 lowestIndex = ctx->lowLimit;
|
||||
const U32 dictLimit = ctx->dictLimit;
|
||||
const BYTE* const prefixStart = base + dictLimit;
|
||||
const BYTE* const dictBase = ctx->dictBase;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
|
||||
const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
|
||||
const U32 sufficient_len = ctx->appliedParams.cParams.targetLength;
|
||||
const U32 mls = ctx->appliedParams.cParams.searchLength;
|
||||
const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
|
||||
|
||||
ZSTD_optimal_t* opt = optStatePtr->priceTable;
|
||||
ZSTD_match_t* matches = optStatePtr->matchTable;
|
||||
const BYTE* inr;
|
||||
|
||||
/* init */
|
||||
U32 offset, rep[ZSTD_REP_NUM];
|
||||
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; }
|
||||
|
||||
ctx->nextToUpdate3 = ctx->nextToUpdate;
|
||||
ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
|
||||
ip += (ip==prefixStart);
|
||||
|
||||
/* Match Loop */
|
||||
while (ip < ilimit) {
|
||||
U32 cur, match_num, last_pos, litlen, price;
|
||||
U32 u, mlen, best_mlen, best_off, litLength;
|
||||
U32 current = (U32)(ip-base);
|
||||
memset(opt, 0, sizeof(ZSTD_optimal_t));
|
||||
last_pos = 0;
|
||||
opt[0].litlen = (U32)(ip - anchor);
|
||||
|
||||
/* check repCode */
|
||||
{ U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
|
||||
for (i = (ip==anchor); i<last_i; i++) {
|
||||
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i];
|
||||
const U32 repIndex = (U32)(current - repCur);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if ( (repCur > 0 && repCur <= (S32)current)
|
||||
&& (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex)) /* intentional overflow */
|
||||
&& (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
|
||||
/* repcode detected we should take it */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
mlen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
|
||||
|
||||
if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
|
||||
best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
|
||||
best_off = i - (ip==anchor);
|
||||
litlen = opt[0].litlen;
|
||||
do {
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
|
||||
if (mlen > last_pos || price < opt[mlen].price)
|
||||
SET_PRICE(mlen, mlen, i, litlen, price); /* note : macro modifies last_pos */
|
||||
mlen--;
|
||||
} while (mlen >= minMatch);
|
||||
} } }
|
||||
|
||||
match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, ip, iend, maxSearches, mls, matches, minMatch); /* first search (depth 0) */
|
||||
|
||||
if (!last_pos && !match_num) { ip++; continue; }
|
||||
|
||||
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
|
||||
opt[0].mlen = 1;
|
||||
|
||||
if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
|
||||
best_mlen = matches[match_num-1].len;
|
||||
best_off = matches[match_num-1].off;
|
||||
cur = 0;
|
||||
last_pos = 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
|
||||
best_mlen = (last_pos) ? last_pos : minMatch;
|
||||
|
||||
/* set prices using matches at position = 0 */
|
||||
for (u = 0; u < match_num; u++) {
|
||||
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
|
||||
best_mlen = matches[u].len;
|
||||
litlen = opt[0].litlen;
|
||||
while (mlen <= best_mlen) {
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
if (mlen > last_pos || price < opt[mlen].price)
|
||||
SET_PRICE(mlen, mlen, matches[u].off, litlen, price);
|
||||
mlen++;
|
||||
} }
|
||||
|
||||
if (last_pos < minMatch) {
|
||||
ip++; continue;
|
||||
}
|
||||
|
||||
/* check further positions */
|
||||
for (cur = 1; cur <= last_pos; cur++) {
|
||||
inr = ip + cur;
|
||||
|
||||
if (opt[cur-1].mlen == 1) {
|
||||
litlen = opt[cur-1].litlen + 1;
|
||||
if (cur > litlen) {
|
||||
price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen);
|
||||
} else
|
||||
price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor);
|
||||
} else {
|
||||
litlen = 1;
|
||||
price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1);
|
||||
}
|
||||
|
||||
if (cur > last_pos || price <= opt[cur].price)
|
||||
SET_PRICE(cur, 1, 0, litlen, price);
|
||||
|
||||
if (cur == last_pos) break;
|
||||
|
||||
if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */
|
||||
continue;
|
||||
|
||||
mlen = opt[cur].mlen;
|
||||
if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
|
||||
opt[cur].rep[2] = opt[cur-mlen].rep[1];
|
||||
opt[cur].rep[1] = opt[cur-mlen].rep[0];
|
||||
opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
|
||||
} 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]);
|
||||
}
|
||||
|
||||
best_mlen = minMatch;
|
||||
{ U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
|
||||
for (i = (mlen != 1); i<last_i; i++) {
|
||||
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i];
|
||||
const U32 repIndex = (U32)(current+cur - repCur);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if ( (repCur > 0 && repCur <= (S32)(current+cur))
|
||||
&& (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex)) /* intentional overflow */
|
||||
&& (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
|
||||
/* repcode detected */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
mlen = (U32)ZSTD_count_2segments(inr+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
|
||||
|
||||
if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
|
||||
best_mlen = mlen; best_off = i; last_pos = cur + 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
|
||||
best_off = i - (opt[cur].mlen != 1);
|
||||
if (mlen > best_mlen) best_mlen = mlen;
|
||||
|
||||
do {
|
||||
if (opt[cur].mlen == 1) {
|
||||
litlen = opt[cur].litlen;
|
||||
if (cur > litlen) {
|
||||
price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
|
||||
} else
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
|
||||
} else {
|
||||
litlen = 0;
|
||||
price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
|
||||
}
|
||||
|
||||
if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
|
||||
SET_PRICE(cur + mlen, mlen, i, litlen, price);
|
||||
mlen--;
|
||||
} while (mlen >= minMatch);
|
||||
} } }
|
||||
|
||||
match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, inr, iend, maxSearches, mls, matches, minMatch);
|
||||
|
||||
if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
|
||||
best_mlen = matches[match_num-1].len;
|
||||
best_off = matches[match_num-1].off;
|
||||
last_pos = cur + 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
|
||||
/* set prices using matches at position = cur */
|
||||
for (u = 0; u < match_num; u++) {
|
||||
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
|
||||
best_mlen = matches[u].len;
|
||||
|
||||
while (mlen <= best_mlen) {
|
||||
if (opt[cur].mlen == 1) {
|
||||
litlen = opt[cur].litlen;
|
||||
if (cur > litlen)
|
||||
price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
else
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
} else {
|
||||
litlen = 0;
|
||||
price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
}
|
||||
|
||||
if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
|
||||
SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
|
||||
|
||||
mlen++;
|
||||
} } } /* for (cur = 1; cur <= last_pos; cur++) */
|
||||
|
||||
best_mlen = opt[last_pos].mlen;
|
||||
best_off = opt[last_pos].off;
|
||||
cur = last_pos - best_mlen;
|
||||
|
||||
/* store sequence */
|
||||
_storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
|
||||
opt[0].mlen = 1;
|
||||
|
||||
while (1) {
|
||||
mlen = opt[cur].mlen;
|
||||
offset = opt[cur].off;
|
||||
opt[cur].mlen = best_mlen;
|
||||
opt[cur].off = best_off;
|
||||
best_mlen = mlen;
|
||||
best_off = offset;
|
||||
if (mlen > cur) break;
|
||||
cur -= mlen;
|
||||
}
|
||||
|
||||
for (u = 0; u <= last_pos; ) {
|
||||
u += opt[u].mlen;
|
||||
}
|
||||
|
||||
for (cur=0; cur < last_pos; ) {
|
||||
mlen = opt[cur].mlen;
|
||||
if (mlen == 1) { ip++; cur++; continue; }
|
||||
offset = opt[cur].off;
|
||||
cur += mlen;
|
||||
litLength = (U32)(ip - anchor);
|
||||
|
||||
if (offset > ZSTD_REP_MOVE_OPT) {
|
||||
rep[2] = rep[1];
|
||||
rep[1] = rep[0];
|
||||
rep[0] = offset - ZSTD_REP_MOVE_OPT;
|
||||
offset--;
|
||||
} else {
|
||||
if (offset != 0) {
|
||||
best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
|
||||
if (offset != 1) rep[2] = rep[1];
|
||||
rep[1] = rep[0];
|
||||
rep[0] = best_off;
|
||||
}
|
||||
|
||||
if (litLength==0) offset--;
|
||||
}
|
||||
|
||||
ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH);
|
||||
ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
|
||||
anchor = ip = ip + mlen;
|
||||
} } /* for (cur=0; cur < last_pos; ) */
|
||||
|
||||
/* Save reps for next block */
|
||||
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; }
|
||||
|
||||
/* Return the last literals size */
|
||||
return iend - anchor;
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
|
||||
}
|
||||
+922
-14
@@ -5,26 +5,934 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_OPT_H
|
||||
#define ZSTD_OPT_H
|
||||
|
||||
#include "zstd_compress.h"
|
||||
/* Note : this file is intended to be included within zstd_compress.c */
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
#ifndef ZSTD_OPT_H_91842398743
|
||||
#define ZSTD_OPT_H_91842398743
|
||||
|
||||
size_t ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
size_t ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
#define ZSTD_LITFREQ_ADD 2
|
||||
#define ZSTD_FREQ_DIV 4
|
||||
#define ZSTD_MAX_PRICE (1<<30)
|
||||
|
||||
/*-*************************************
|
||||
* Price functions for optimal parser
|
||||
***************************************/
|
||||
static void ZSTD_setLog2Prices(optState_t* optPtr)
|
||||
{
|
||||
optPtr->log2matchLengthSum = ZSTD_highbit32(optPtr->matchLengthSum+1);
|
||||
optPtr->log2litLengthSum = ZSTD_highbit32(optPtr->litLengthSum+1);
|
||||
optPtr->log2litSum = ZSTD_highbit32(optPtr->litSum+1);
|
||||
optPtr->log2offCodeSum = ZSTD_highbit32(optPtr->offCodeSum+1);
|
||||
optPtr->factor = 1 + ((optPtr->litSum>>5) / optPtr->litLengthSum) + ((optPtr->litSum<<1) / (optPtr->litSum + optPtr->matchSum));
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZSTD_OPT_H */
|
||||
|
||||
static void ZSTD_rescaleFreqs(optState_t* optPtr, const BYTE* src, size_t srcSize)
|
||||
{
|
||||
unsigned u;
|
||||
|
||||
optPtr->cachedLiterals = NULL;
|
||||
optPtr->cachedPrice = optPtr->cachedLitLength = 0;
|
||||
optPtr->staticPrices = 0;
|
||||
|
||||
if (optPtr->litLengthSum == 0) {
|
||||
if (srcSize <= 1024) optPtr->staticPrices = 1;
|
||||
|
||||
assert(optPtr->litFreq!=NULL);
|
||||
for (u=0; u<=MaxLit; u++)
|
||||
optPtr->litFreq[u] = 0;
|
||||
for (u=0; u<srcSize; u++)
|
||||
optPtr->litFreq[src[u]]++;
|
||||
|
||||
optPtr->litSum = 0;
|
||||
optPtr->litLengthSum = MaxLL+1;
|
||||
optPtr->matchLengthSum = MaxML+1;
|
||||
optPtr->offCodeSum = (MaxOff+1);
|
||||
optPtr->matchSum = (ZSTD_LITFREQ_ADD<<Litbits);
|
||||
|
||||
for (u=0; u<=MaxLit; u++) {
|
||||
optPtr->litFreq[u] = 1 + (optPtr->litFreq[u]>>ZSTD_FREQ_DIV);
|
||||
optPtr->litSum += optPtr->litFreq[u];
|
||||
}
|
||||
for (u=0; u<=MaxLL; u++)
|
||||
optPtr->litLengthFreq[u] = 1;
|
||||
for (u=0; u<=MaxML; u++)
|
||||
optPtr->matchLengthFreq[u] = 1;
|
||||
for (u=0; u<=MaxOff; u++)
|
||||
optPtr->offCodeFreq[u] = 1;
|
||||
} else {
|
||||
optPtr->matchLengthSum = 0;
|
||||
optPtr->litLengthSum = 0;
|
||||
optPtr->offCodeSum = 0;
|
||||
optPtr->matchSum = 0;
|
||||
optPtr->litSum = 0;
|
||||
|
||||
for (u=0; u<=MaxLit; u++) {
|
||||
optPtr->litFreq[u] = 1 + (optPtr->litFreq[u]>>(ZSTD_FREQ_DIV+1));
|
||||
optPtr->litSum += optPtr->litFreq[u];
|
||||
}
|
||||
for (u=0; u<=MaxLL; u++) {
|
||||
optPtr->litLengthFreq[u] = 1 + (optPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1));
|
||||
optPtr->litLengthSum += optPtr->litLengthFreq[u];
|
||||
}
|
||||
for (u=0; u<=MaxML; u++) {
|
||||
optPtr->matchLengthFreq[u] = 1 + (optPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV);
|
||||
optPtr->matchLengthSum += optPtr->matchLengthFreq[u];
|
||||
optPtr->matchSum += optPtr->matchLengthFreq[u] * (u + 3);
|
||||
}
|
||||
optPtr->matchSum *= ZSTD_LITFREQ_ADD;
|
||||
for (u=0; u<=MaxOff; u++) {
|
||||
optPtr->offCodeFreq[u] = 1 + (optPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV);
|
||||
optPtr->offCodeSum += optPtr->offCodeFreq[u];
|
||||
}
|
||||
}
|
||||
|
||||
ZSTD_setLog2Prices(optPtr);
|
||||
}
|
||||
|
||||
|
||||
static U32 ZSTD_getLiteralPrice(optState_t* optPtr, U32 litLength, const BYTE* literals)
|
||||
{
|
||||
U32 price, u;
|
||||
|
||||
if (optPtr->staticPrices)
|
||||
return ZSTD_highbit32((U32)litLength+1) + (litLength*6);
|
||||
|
||||
if (litLength == 0)
|
||||
return optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[0]+1);
|
||||
|
||||
/* literals */
|
||||
if (optPtr->cachedLiterals == literals) {
|
||||
U32 const additional = litLength - optPtr->cachedLitLength;
|
||||
const BYTE* literals2 = optPtr->cachedLiterals + optPtr->cachedLitLength;
|
||||
price = optPtr->cachedPrice + additional * optPtr->log2litSum;
|
||||
for (u=0; u < additional; u++)
|
||||
price -= ZSTD_highbit32(optPtr->litFreq[literals2[u]]+1);
|
||||
optPtr->cachedPrice = price;
|
||||
optPtr->cachedLitLength = litLength;
|
||||
} else {
|
||||
price = litLength * optPtr->log2litSum;
|
||||
for (u=0; u < litLength; u++)
|
||||
price -= ZSTD_highbit32(optPtr->litFreq[literals[u]]+1);
|
||||
|
||||
if (litLength >= 12) {
|
||||
optPtr->cachedLiterals = literals;
|
||||
optPtr->cachedPrice = price;
|
||||
optPtr->cachedLitLength = litLength;
|
||||
}
|
||||
}
|
||||
|
||||
/* literal Length */
|
||||
{ const BYTE LL_deltaCode = 19;
|
||||
const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
|
||||
price += LL_bits[llCode] + optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1);
|
||||
}
|
||||
|
||||
return price;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE U32 ZSTD_getPrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength, const int ultra)
|
||||
{
|
||||
/* offset */
|
||||
U32 price;
|
||||
BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
|
||||
|
||||
if (optPtr->staticPrices)
|
||||
return ZSTD_getLiteralPrice(optPtr, litLength, literals) + ZSTD_highbit32((U32)matchLength+1) + 16 + offCode;
|
||||
|
||||
price = offCode + optPtr->log2offCodeSum - ZSTD_highbit32(optPtr->offCodeFreq[offCode]+1);
|
||||
if (!ultra && offCode >= 20) price += (offCode-19)*2;
|
||||
|
||||
/* match Length */
|
||||
{ const BYTE ML_deltaCode = 36;
|
||||
const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
|
||||
price += ML_bits[mlCode] + optPtr->log2matchLengthSum - ZSTD_highbit32(optPtr->matchLengthFreq[mlCode]+1);
|
||||
}
|
||||
|
||||
return price + ZSTD_getLiteralPrice(optPtr, litLength, literals) + optPtr->factor;
|
||||
}
|
||||
|
||||
|
||||
static void ZSTD_updatePrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength)
|
||||
{
|
||||
U32 u;
|
||||
|
||||
/* literals */
|
||||
optPtr->litSum += litLength*ZSTD_LITFREQ_ADD;
|
||||
for (u=0; u < litLength; u++)
|
||||
optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
|
||||
|
||||
/* literal Length */
|
||||
{ const BYTE LL_deltaCode = 19;
|
||||
const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
|
||||
optPtr->litLengthFreq[llCode]++;
|
||||
optPtr->litLengthSum++;
|
||||
}
|
||||
|
||||
/* match offset */
|
||||
{ BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
|
||||
optPtr->offCodeSum++;
|
||||
optPtr->offCodeFreq[offCode]++;
|
||||
}
|
||||
|
||||
/* match Length */
|
||||
{ const BYTE ML_deltaCode = 36;
|
||||
const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
|
||||
optPtr->matchLengthFreq[mlCode]++;
|
||||
optPtr->matchLengthSum++;
|
||||
}
|
||||
|
||||
ZSTD_setLog2Prices(optPtr);
|
||||
}
|
||||
|
||||
|
||||
#define SET_PRICE(pos, mlen_, offset_, litlen_, price_) \
|
||||
{ \
|
||||
while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } \
|
||||
opt[pos].mlen = mlen_; \
|
||||
opt[pos].off = offset_; \
|
||||
opt[pos].litlen = litlen_; \
|
||||
opt[pos].price = price_; \
|
||||
}
|
||||
|
||||
|
||||
/* function safe only for comparisons */
|
||||
static U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
|
||||
{
|
||||
switch (length)
|
||||
{
|
||||
default :
|
||||
case 4 : return MEM_read32(memPtr);
|
||||
case 3 : if (MEM_isLittleEndian())
|
||||
return MEM_read32(memPtr)<<8;
|
||||
else
|
||||
return MEM_read32(memPtr)>>8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Update hashTable3 up to ip (excluded)
|
||||
Assumption : always within prefix (i.e. not within extDict) */
|
||||
static
|
||||
U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* zc, const BYTE* ip)
|
||||
{
|
||||
U32* const hashTable3 = zc->hashTable3;
|
||||
U32 const hashLog3 = zc->hashLog3;
|
||||
const BYTE* const base = zc->base;
|
||||
U32 idx = zc->nextToUpdate3;
|
||||
const U32 target = zc->nextToUpdate3 = (U32)(ip - base);
|
||||
const size_t hash3 = ZSTD_hash3Ptr(ip, hashLog3);
|
||||
|
||||
while(idx < target) {
|
||||
hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
|
||||
idx++;
|
||||
}
|
||||
|
||||
return hashTable3[hash3];
|
||||
}
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Binary Tree search
|
||||
***************************************/
|
||||
static U32 ZSTD_insertBtAndGetAllMatches (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
U32 nbCompares, const U32 mls,
|
||||
U32 extDict, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||
{
|
||||
const BYTE* const base = zc->base;
|
||||
const U32 current = (U32)(ip-base);
|
||||
const U32 hashLog = zc->appliedParams.cParams.hashLog;
|
||||
const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
|
||||
U32* const hashTable = zc->hashTable;
|
||||
U32 matchIndex = hashTable[h];
|
||||
U32* const bt = zc->chainTable;
|
||||
const U32 btLog = zc->appliedParams.cParams.chainLog - 1;
|
||||
const U32 btMask= (1U << btLog) - 1;
|
||||
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
||||
const BYTE* const dictBase = zc->dictBase;
|
||||
const U32 dictLimit = zc->dictLimit;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const prefixStart = base + dictLimit;
|
||||
const U32 btLow = btMask >= current ? 0 : current - btMask;
|
||||
const U32 windowLow = zc->lowLimit;
|
||||
U32* smallerPtr = bt + 2*(current&btMask);
|
||||
U32* largerPtr = bt + 2*(current&btMask) + 1;
|
||||
U32 matchEndIdx = current+8;
|
||||
U32 dummy32; /* to be nullified at the end */
|
||||
U32 mnum = 0;
|
||||
|
||||
const U32 minMatch = (mls == 3) ? 3 : 4;
|
||||
size_t bestLength = minMatchLen-1;
|
||||
|
||||
if (minMatch == 3) { /* HC3 match finder */
|
||||
U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip);
|
||||
if (matchIndex3>windowLow && (current - matchIndex3 < (1<<18))) {
|
||||
const BYTE* match;
|
||||
size_t currentMl=0;
|
||||
if ((!extDict) || matchIndex3 >= dictLimit) {
|
||||
match = base + matchIndex3;
|
||||
if (match[bestLength] == ip[bestLength]) currentMl = ZSTD_count(ip, match, iLimit);
|
||||
} else {
|
||||
match = dictBase + matchIndex3;
|
||||
if (ZSTD_readMINMATCH(match, MINMATCH) == ZSTD_readMINMATCH(ip, MINMATCH)) /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */
|
||||
currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
|
||||
}
|
||||
|
||||
/* save best solution */
|
||||
if (currentMl > bestLength) {
|
||||
bestLength = currentMl;
|
||||
matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex3;
|
||||
matches[mnum].len = (U32)currentMl;
|
||||
mnum++;
|
||||
if (currentMl > ZSTD_OPT_NUM) goto update;
|
||||
if (ip+currentMl == iLimit) goto update; /* best possible, and avoid read overflow*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hashTable[h] = current; /* Update Hash Table */
|
||||
|
||||
while (nbCompares-- && (matchIndex > windowLow)) {
|
||||
U32* nextPtr = bt + 2*(matchIndex & btMask);
|
||||
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||
const BYTE* match;
|
||||
|
||||
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
|
||||
match = base + matchIndex;
|
||||
if (match[matchLength] == ip[matchLength]) {
|
||||
matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iLimit) +1;
|
||||
}
|
||||
} else {
|
||||
match = dictBase + matchIndex;
|
||||
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
|
||||
if (matchIndex+matchLength >= dictLimit)
|
||||
match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
|
||||
}
|
||||
|
||||
if (matchLength > bestLength) {
|
||||
if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength;
|
||||
bestLength = matchLength;
|
||||
matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex;
|
||||
matches[mnum].len = (U32)matchLength;
|
||||
mnum++;
|
||||
if (matchLength > ZSTD_OPT_NUM) break;
|
||||
if (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */
|
||||
break; /* drop, to guarantee consistency (miss a little bit of compression) */
|
||||
}
|
||||
|
||||
if (match[matchLength] < ip[matchLength]) {
|
||||
/* match is smaller than current */
|
||||
*smallerPtr = matchIndex; /* update smaller idx */
|
||||
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
|
||||
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||
smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
|
||||
matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
|
||||
} else {
|
||||
/* match is larger than current */
|
||||
*largerPtr = matchIndex;
|
||||
commonLengthLarger = matchLength;
|
||||
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
||||
largerPtr = nextPtr;
|
||||
matchIndex = nextPtr[0];
|
||||
} }
|
||||
|
||||
*smallerPtr = *largerPtr = 0;
|
||||
|
||||
update:
|
||||
zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
|
||||
return mnum;
|
||||
}
|
||||
|
||||
|
||||
/** Tree updater, providing best match */
|
||||
static U32 ZSTD_BtGetAllMatches (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||
{
|
||||
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
|
||||
ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
|
||||
return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches, minMatchLen);
|
||||
}
|
||||
|
||||
|
||||
static U32 ZSTD_BtGetAllMatches_selectMLS (
|
||||
ZSTD_CCtx* zc, /* Index table will be updated */
|
||||
const BYTE* ip, const BYTE* const iHighLimit,
|
||||
const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||
{
|
||||
switch(matchLengthSearch)
|
||||
{
|
||||
case 3 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
|
||||
default :
|
||||
case 4 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
|
||||
case 5 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
|
||||
}
|
||||
}
|
||||
|
||||
/** Tree updater, providing best match */
|
||||
static U32 ZSTD_BtGetAllMatches_extDict (
|
||||
ZSTD_CCtx* zc,
|
||||
const BYTE* const ip, const BYTE* const iLimit,
|
||||
const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||
{
|
||||
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
|
||||
ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
|
||||
return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minMatchLen);
|
||||
}
|
||||
|
||||
|
||||
static U32 ZSTD_BtGetAllMatches_selectMLS_extDict (
|
||||
ZSTD_CCtx* zc, /* Index table will be updated */
|
||||
const BYTE* ip, const BYTE* const iHighLimit,
|
||||
const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
|
||||
{
|
||||
switch(matchLengthSearch)
|
||||
{
|
||||
case 3 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
|
||||
default :
|
||||
case 4 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
|
||||
case 5 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
|
||||
case 7 :
|
||||
case 6 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-*******************************
|
||||
* Optimal parser
|
||||
*********************************/
|
||||
FORCE_INLINE_TEMPLATE
|
||||
void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize, const int ultra)
|
||||
{
|
||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
||||
optState_t* optStatePtr = &(ctx->optState);
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
const BYTE* const base = ctx->base;
|
||||
const BYTE* const prefixStart = base + ctx->dictLimit;
|
||||
|
||||
const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
|
||||
const U32 sufficient_len = ctx->appliedParams.cParams.targetLength;
|
||||
const U32 mls = ctx->appliedParams.cParams.searchLength;
|
||||
const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
|
||||
|
||||
ZSTD_optimal_t* opt = optStatePtr->priceTable;
|
||||
ZSTD_match_t* matches = optStatePtr->matchTable;
|
||||
const BYTE* inr;
|
||||
U32 offset, rep[ZSTD_REP_NUM];
|
||||
|
||||
/* init */
|
||||
ctx->nextToUpdate3 = ctx->nextToUpdate;
|
||||
ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
|
||||
ip += (ip==prefixStart);
|
||||
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; }
|
||||
|
||||
/* Match Loop */
|
||||
while (ip < ilimit) {
|
||||
U32 cur, match_num, last_pos, litlen, price;
|
||||
U32 u, mlen, best_mlen, best_off, litLength;
|
||||
memset(opt, 0, sizeof(ZSTD_optimal_t));
|
||||
last_pos = 0;
|
||||
litlen = (U32)(ip - anchor);
|
||||
|
||||
/* check repCode */
|
||||
{ U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
|
||||
for (i=(ip == anchor); i<last_i; i++) {
|
||||
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i];
|
||||
if ( (repCur > 0) && (repCur < (S32)(ip-prefixStart))
|
||||
&& (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repCur, minMatch))) {
|
||||
mlen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repCur, iend) + minMatch;
|
||||
if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
|
||||
best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
best_off = i - (ip == anchor);
|
||||
do {
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
|
||||
if (mlen > last_pos || price < opt[mlen].price)
|
||||
SET_PRICE(mlen, mlen, i, litlen, price); /* note : macro modifies last_pos */
|
||||
mlen--;
|
||||
} while (mlen >= minMatch);
|
||||
} } }
|
||||
|
||||
match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, ip, iend, maxSearches, mls, matches, minMatch);
|
||||
|
||||
if (!last_pos && !match_num) { ip++; continue; }
|
||||
|
||||
if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
|
||||
best_mlen = matches[match_num-1].len;
|
||||
best_off = matches[match_num-1].off;
|
||||
cur = 0;
|
||||
last_pos = 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
|
||||
/* set prices using matches at position = 0 */
|
||||
best_mlen = (last_pos) ? last_pos : minMatch;
|
||||
for (u = 0; u < match_num; u++) {
|
||||
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
|
||||
best_mlen = matches[u].len;
|
||||
while (mlen <= best_mlen) {
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
if (mlen > last_pos || price < opt[mlen].price)
|
||||
SET_PRICE(mlen, mlen, matches[u].off, litlen, price); /* note : macro modifies last_pos */
|
||||
mlen++;
|
||||
} }
|
||||
|
||||
if (last_pos < minMatch) { ip++; continue; }
|
||||
|
||||
/* initialize opt[0] */
|
||||
{ U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
|
||||
opt[0].mlen = 1;
|
||||
opt[0].litlen = litlen;
|
||||
|
||||
/* check further positions */
|
||||
for (cur = 1; cur <= last_pos; cur++) {
|
||||
inr = ip + cur;
|
||||
|
||||
if (opt[cur-1].mlen == 1) {
|
||||
litlen = opt[cur-1].litlen + 1;
|
||||
if (cur > litlen) {
|
||||
price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen);
|
||||
} else
|
||||
price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor);
|
||||
} else {
|
||||
litlen = 1;
|
||||
price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1);
|
||||
}
|
||||
|
||||
if (cur > last_pos || price <= opt[cur].price)
|
||||
SET_PRICE(cur, 1, 0, litlen, price);
|
||||
|
||||
if (cur == last_pos) break;
|
||||
|
||||
if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */
|
||||
continue;
|
||||
|
||||
mlen = opt[cur].mlen;
|
||||
if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
|
||||
opt[cur].rep[2] = opt[cur-mlen].rep[1];
|
||||
opt[cur].rep[1] = opt[cur-mlen].rep[0];
|
||||
opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
|
||||
} 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]);
|
||||
}
|
||||
|
||||
best_mlen = minMatch;
|
||||
{ U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
|
||||
for (i=(opt[cur].mlen != 1); i<last_i; i++) { /* check rep */
|
||||
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i];
|
||||
if ( (repCur > 0) && (repCur < (S32)(inr-prefixStart))
|
||||
&& (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(inr - repCur, minMatch))) {
|
||||
mlen = (U32)ZSTD_count(inr+minMatch, inr+minMatch - repCur, iend) + minMatch;
|
||||
|
||||
if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
|
||||
best_mlen = mlen; best_off = i; last_pos = cur + 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
|
||||
best_off = i - (opt[cur].mlen != 1);
|
||||
if (mlen > best_mlen) best_mlen = mlen;
|
||||
|
||||
do {
|
||||
if (opt[cur].mlen == 1) {
|
||||
litlen = opt[cur].litlen;
|
||||
if (cur > litlen) {
|
||||
price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
|
||||
} else
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
|
||||
} else {
|
||||
litlen = 0;
|
||||
price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
|
||||
}
|
||||
|
||||
if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
|
||||
SET_PRICE(cur + mlen, mlen, i, litlen, price);
|
||||
mlen--;
|
||||
} while (mlen >= minMatch);
|
||||
} } }
|
||||
|
||||
match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, inr, iend, maxSearches, mls, matches, best_mlen);
|
||||
|
||||
if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
|
||||
best_mlen = matches[match_num-1].len;
|
||||
best_off = matches[match_num-1].off;
|
||||
last_pos = cur + 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
|
||||
/* set prices using matches at position = cur */
|
||||
for (u = 0; u < match_num; u++) {
|
||||
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
|
||||
best_mlen = matches[u].len;
|
||||
|
||||
while (mlen <= best_mlen) {
|
||||
if (opt[cur].mlen == 1) {
|
||||
litlen = opt[cur].litlen;
|
||||
if (cur > litlen)
|
||||
price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
else
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
} else {
|
||||
litlen = 0;
|
||||
price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
}
|
||||
|
||||
if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
|
||||
SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
|
||||
|
||||
mlen++;
|
||||
} } }
|
||||
|
||||
best_mlen = opt[last_pos].mlen;
|
||||
best_off = opt[last_pos].off;
|
||||
cur = last_pos - best_mlen;
|
||||
|
||||
/* store sequence */
|
||||
_storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
|
||||
opt[0].mlen = 1;
|
||||
|
||||
while (1) {
|
||||
mlen = opt[cur].mlen;
|
||||
offset = opt[cur].off;
|
||||
opt[cur].mlen = best_mlen;
|
||||
opt[cur].off = best_off;
|
||||
best_mlen = mlen;
|
||||
best_off = offset;
|
||||
if (mlen > cur) break;
|
||||
cur -= mlen;
|
||||
}
|
||||
|
||||
for (u = 0; u <= last_pos;) {
|
||||
u += opt[u].mlen;
|
||||
}
|
||||
|
||||
for (cur=0; cur < last_pos; ) {
|
||||
mlen = opt[cur].mlen;
|
||||
if (mlen == 1) { ip++; cur++; continue; }
|
||||
offset = opt[cur].off;
|
||||
cur += mlen;
|
||||
litLength = (U32)(ip - anchor);
|
||||
|
||||
if (offset > ZSTD_REP_MOVE_OPT) {
|
||||
rep[2] = rep[1];
|
||||
rep[1] = rep[0];
|
||||
rep[0] = offset - ZSTD_REP_MOVE_OPT;
|
||||
offset--;
|
||||
} else {
|
||||
if (offset != 0) {
|
||||
best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
|
||||
if (offset != 1) rep[2] = rep[1];
|
||||
rep[1] = rep[0];
|
||||
rep[0] = best_off;
|
||||
}
|
||||
if (litLength==0) offset--;
|
||||
}
|
||||
|
||||
ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH);
|
||||
ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
|
||||
anchor = ip = ip + mlen;
|
||||
} } /* for (cur=0; cur < last_pos; ) */
|
||||
|
||||
/* Save reps for next block */
|
||||
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; }
|
||||
|
||||
/* Last Literals */
|
||||
{ size_t const lastLLSize = iend - anchor;
|
||||
memcpy(seqStorePtr->lit, anchor, lastLLSize);
|
||||
seqStorePtr->lit += lastLLSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx,
|
||||
const void* src, size_t srcSize, const int ultra)
|
||||
{
|
||||
seqStore_t* seqStorePtr = &(ctx->seqStore);
|
||||
optState_t* optStatePtr = &(ctx->optState);
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
const BYTE* const base = ctx->base;
|
||||
const U32 lowestIndex = ctx->lowLimit;
|
||||
const U32 dictLimit = ctx->dictLimit;
|
||||
const BYTE* const prefixStart = base + dictLimit;
|
||||
const BYTE* const dictBase = ctx->dictBase;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
|
||||
const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
|
||||
const U32 sufficient_len = ctx->appliedParams.cParams.targetLength;
|
||||
const U32 mls = ctx->appliedParams.cParams.searchLength;
|
||||
const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
|
||||
|
||||
ZSTD_optimal_t* opt = optStatePtr->priceTable;
|
||||
ZSTD_match_t* matches = optStatePtr->matchTable;
|
||||
const BYTE* inr;
|
||||
|
||||
/* init */
|
||||
U32 offset, rep[ZSTD_REP_NUM];
|
||||
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; }
|
||||
|
||||
ctx->nextToUpdate3 = ctx->nextToUpdate;
|
||||
ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
|
||||
ip += (ip==prefixStart);
|
||||
|
||||
/* Match Loop */
|
||||
while (ip < ilimit) {
|
||||
U32 cur, match_num, last_pos, litlen, price;
|
||||
U32 u, mlen, best_mlen, best_off, litLength;
|
||||
U32 current = (U32)(ip-base);
|
||||
memset(opt, 0, sizeof(ZSTD_optimal_t));
|
||||
last_pos = 0;
|
||||
opt[0].litlen = (U32)(ip - anchor);
|
||||
|
||||
/* check repCode */
|
||||
{ U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
|
||||
for (i = (ip==anchor); i<last_i; i++) {
|
||||
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i];
|
||||
const U32 repIndex = (U32)(current - repCur);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if ( (repCur > 0 && repCur <= (S32)current)
|
||||
&& (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex)) /* intentional overflow */
|
||||
&& (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
|
||||
/* repcode detected we should take it */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
mlen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
|
||||
|
||||
if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
|
||||
best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
|
||||
best_off = i - (ip==anchor);
|
||||
litlen = opt[0].litlen;
|
||||
do {
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
|
||||
if (mlen > last_pos || price < opt[mlen].price)
|
||||
SET_PRICE(mlen, mlen, i, litlen, price); /* note : macro modifies last_pos */
|
||||
mlen--;
|
||||
} while (mlen >= minMatch);
|
||||
} } }
|
||||
|
||||
match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, ip, iend, maxSearches, mls, matches, minMatch); /* first search (depth 0) */
|
||||
|
||||
if (!last_pos && !match_num) { ip++; continue; }
|
||||
|
||||
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
|
||||
opt[0].mlen = 1;
|
||||
|
||||
if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
|
||||
best_mlen = matches[match_num-1].len;
|
||||
best_off = matches[match_num-1].off;
|
||||
cur = 0;
|
||||
last_pos = 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
|
||||
best_mlen = (last_pos) ? last_pos : minMatch;
|
||||
|
||||
/* set prices using matches at position = 0 */
|
||||
for (u = 0; u < match_num; u++) {
|
||||
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
|
||||
best_mlen = matches[u].len;
|
||||
litlen = opt[0].litlen;
|
||||
while (mlen <= best_mlen) {
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
if (mlen > last_pos || price < opt[mlen].price)
|
||||
SET_PRICE(mlen, mlen, matches[u].off, litlen, price);
|
||||
mlen++;
|
||||
} }
|
||||
|
||||
if (last_pos < minMatch) {
|
||||
ip++; continue;
|
||||
}
|
||||
|
||||
/* check further positions */
|
||||
for (cur = 1; cur <= last_pos; cur++) {
|
||||
inr = ip + cur;
|
||||
|
||||
if (opt[cur-1].mlen == 1) {
|
||||
litlen = opt[cur-1].litlen + 1;
|
||||
if (cur > litlen) {
|
||||
price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen);
|
||||
} else
|
||||
price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor);
|
||||
} else {
|
||||
litlen = 1;
|
||||
price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1);
|
||||
}
|
||||
|
||||
if (cur > last_pos || price <= opt[cur].price)
|
||||
SET_PRICE(cur, 1, 0, litlen, price);
|
||||
|
||||
if (cur == last_pos) break;
|
||||
|
||||
if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */
|
||||
continue;
|
||||
|
||||
mlen = opt[cur].mlen;
|
||||
if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
|
||||
opt[cur].rep[2] = opt[cur-mlen].rep[1];
|
||||
opt[cur].rep[1] = opt[cur-mlen].rep[0];
|
||||
opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
|
||||
} 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]);
|
||||
}
|
||||
|
||||
best_mlen = minMatch;
|
||||
{ U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
|
||||
for (i = (mlen != 1); i<last_i; i++) {
|
||||
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i];
|
||||
const U32 repIndex = (U32)(current+cur - repCur);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if ( (repCur > 0 && repCur <= (S32)(current+cur))
|
||||
&& (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex)) /* intentional overflow */
|
||||
&& (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
|
||||
/* repcode detected */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
mlen = (U32)ZSTD_count_2segments(inr+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
|
||||
|
||||
if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
|
||||
best_mlen = mlen; best_off = i; last_pos = cur + 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
|
||||
best_off = i - (opt[cur].mlen != 1);
|
||||
if (mlen > best_mlen) best_mlen = mlen;
|
||||
|
||||
do {
|
||||
if (opt[cur].mlen == 1) {
|
||||
litlen = opt[cur].litlen;
|
||||
if (cur > litlen) {
|
||||
price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
|
||||
} else
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
|
||||
} else {
|
||||
litlen = 0;
|
||||
price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
|
||||
}
|
||||
|
||||
if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
|
||||
SET_PRICE(cur + mlen, mlen, i, litlen, price);
|
||||
mlen--;
|
||||
} while (mlen >= minMatch);
|
||||
} } }
|
||||
|
||||
match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, inr, iend, maxSearches, mls, matches, minMatch);
|
||||
|
||||
if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
|
||||
best_mlen = matches[match_num-1].len;
|
||||
best_off = matches[match_num-1].off;
|
||||
last_pos = cur + 1;
|
||||
goto _storeSequence;
|
||||
}
|
||||
|
||||
/* set prices using matches at position = cur */
|
||||
for (u = 0; u < match_num; u++) {
|
||||
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
|
||||
best_mlen = matches[u].len;
|
||||
|
||||
while (mlen <= best_mlen) {
|
||||
if (opt[cur].mlen == 1) {
|
||||
litlen = opt[cur].litlen;
|
||||
if (cur > litlen)
|
||||
price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
else
|
||||
price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
} else {
|
||||
litlen = 0;
|
||||
price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
|
||||
}
|
||||
|
||||
if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
|
||||
SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
|
||||
|
||||
mlen++;
|
||||
} } } /* for (cur = 1; cur <= last_pos; cur++) */
|
||||
|
||||
best_mlen = opt[last_pos].mlen;
|
||||
best_off = opt[last_pos].off;
|
||||
cur = last_pos - best_mlen;
|
||||
|
||||
/* store sequence */
|
||||
_storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
|
||||
opt[0].mlen = 1;
|
||||
|
||||
while (1) {
|
||||
mlen = opt[cur].mlen;
|
||||
offset = opt[cur].off;
|
||||
opt[cur].mlen = best_mlen;
|
||||
opt[cur].off = best_off;
|
||||
best_mlen = mlen;
|
||||
best_off = offset;
|
||||
if (mlen > cur) break;
|
||||
cur -= mlen;
|
||||
}
|
||||
|
||||
for (u = 0; u <= last_pos; ) {
|
||||
u += opt[u].mlen;
|
||||
}
|
||||
|
||||
for (cur=0; cur < last_pos; ) {
|
||||
mlen = opt[cur].mlen;
|
||||
if (mlen == 1) { ip++; cur++; continue; }
|
||||
offset = opt[cur].off;
|
||||
cur += mlen;
|
||||
litLength = (U32)(ip - anchor);
|
||||
|
||||
if (offset > ZSTD_REP_MOVE_OPT) {
|
||||
rep[2] = rep[1];
|
||||
rep[1] = rep[0];
|
||||
rep[0] = offset - ZSTD_REP_MOVE_OPT;
|
||||
offset--;
|
||||
} else {
|
||||
if (offset != 0) {
|
||||
best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
|
||||
if (offset != 1) rep[2] = rep[1];
|
||||
rep[1] = rep[0];
|
||||
rep[0] = best_off;
|
||||
}
|
||||
|
||||
if (litLength==0) offset--;
|
||||
}
|
||||
|
||||
ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH);
|
||||
ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
|
||||
anchor = ip = ip + mlen;
|
||||
} } /* for (cur=0; cur < last_pos; ) */
|
||||
|
||||
/* Save reps for next block */
|
||||
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; }
|
||||
|
||||
/* Last Literals */
|
||||
{ size_t lastLLSize = iend - anchor;
|
||||
memcpy(seqStorePtr->lit, anchor, lastLLSize);
|
||||
seqStorePtr->lit += lastLLSize;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* ZSTD_OPT_H_91842398743 */
|
||||
|
||||
+56
-123
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -187,20 +186,6 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf)
|
||||
ZSTD_free(buf.start, bufPool->cMem);
|
||||
}
|
||||
|
||||
/* Sets parameters relevant to the compression job, initializing others to
|
||||
* default values. Notably, nbThreads should probably be zero. */
|
||||
static ZSTD_CCtx_params ZSTDMT_makeJobCCtxParams(ZSTD_CCtx_params const params)
|
||||
{
|
||||
ZSTD_CCtx_params jobParams;
|
||||
memset(&jobParams, 0, sizeof(jobParams));
|
||||
|
||||
jobParams.cParams = params.cParams;
|
||||
jobParams.fParams = params.fParams;
|
||||
jobParams.compressionLevel = params.compressionLevel;
|
||||
|
||||
jobParams.ldmParams = params.ldmParams;
|
||||
return jobParams;
|
||||
}
|
||||
|
||||
/* ===== CCtx Pool ===== */
|
||||
/* a single CCtx Pool can be invoked from multiple threads in parallel */
|
||||
@@ -307,7 +292,7 @@ typedef struct {
|
||||
unsigned jobScanned;
|
||||
pthread_mutex_t* jobCompleted_mutex;
|
||||
pthread_cond_t* jobCompleted_cond;
|
||||
ZSTD_CCtx_params params;
|
||||
ZSTD_parameters params;
|
||||
const ZSTD_CDict* cdict;
|
||||
ZSTDMT_CCtxPool* cctxPool;
|
||||
ZSTDMT_bufferPool* bufPool;
|
||||
@@ -344,15 +329,10 @@ void ZSTDMT_compressChunk(void* jobDescription)
|
||||
if (ZSTD_isError(initError)) { job->cSize = initError; goto _endJob; }
|
||||
} else { /* srcStart points at reloaded section */
|
||||
if (!job->firstChunk) job->params.fParams.contentSizeFlag = 0; /* ensure no srcSize control */
|
||||
{ ZSTD_CCtx_params jobParams = job->params;
|
||||
size_t const forceWindowError =
|
||||
ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk);
|
||||
/* Force loading dictionary in "content-only" mode (no header analysis) */
|
||||
size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, job->srcStart, job->dictSize, ZSTD_dm_rawContent, jobParams, job->fullFrameSize);
|
||||
if (ZSTD_isError(initError) || ZSTD_isError(forceWindowError)) {
|
||||
job->cSize = initError;
|
||||
goto _endJob;
|
||||
}
|
||||
{ size_t const dictModeError = ZSTD_setCCtxParameter(cctx, ZSTD_p_forceRawDict, 1); /* Force loading dictionary in "content-only" mode (no header analysis) */
|
||||
size_t const initError = ZSTD_compressBegin_advanced(cctx, job->srcStart, job->dictSize, job->params, job->fullFrameSize);
|
||||
if (ZSTD_isError(initError) || ZSTD_isError(dictModeError)) { job->cSize = initError; goto _endJob; }
|
||||
ZSTD_setCCtxParameter(cctx, ZSTD_p_forceWindow, 1);
|
||||
} }
|
||||
if (!job->firstChunk) { /* flush and overwrite frame header when it's not first segment */
|
||||
size_t const hSize = ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, 0);
|
||||
@@ -402,14 +382,17 @@ struct ZSTDMT_CCtx_s {
|
||||
size_t dictSize;
|
||||
size_t targetDictSize;
|
||||
inBuff_t inBuff;
|
||||
ZSTD_CCtx_params params;
|
||||
ZSTD_parameters params;
|
||||
XXH64_state_t xxhState;
|
||||
unsigned nbThreads;
|
||||
unsigned jobIDMask;
|
||||
unsigned doneJobID;
|
||||
unsigned nextJobID;
|
||||
unsigned frameEnded;
|
||||
unsigned allJobsCompleted;
|
||||
unsigned overlapLog;
|
||||
unsigned long long frameContentSize;
|
||||
size_t sectionSize;
|
||||
ZSTD_customMem cMem;
|
||||
ZSTD_CDict* cdictLocal;
|
||||
const ZSTD_CDict* cdict;
|
||||
@@ -424,15 +407,6 @@ static ZSTDMT_jobDescription* ZSTDMT_allocJobsTable(U32* nbJobsPtr, ZSTD_customM
|
||||
nbJobs * sizeof(ZSTDMT_jobDescription), cMem);
|
||||
}
|
||||
|
||||
/* Internal only */
|
||||
size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads)
|
||||
{
|
||||
params->nbThreads = nbThreads;
|
||||
params->overlapSizeLog = ZSTDMT_OVERLAPLOG_DEFAULT;
|
||||
params->jobSize = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem)
|
||||
{
|
||||
ZSTDMT_CCtx* mtctx;
|
||||
@@ -447,10 +421,12 @@ ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem)
|
||||
|
||||
mtctx = (ZSTDMT_CCtx*) ZSTD_calloc(sizeof(ZSTDMT_CCtx), cMem);
|
||||
if (!mtctx) return NULL;
|
||||
ZSTDMT_initializeCCtxParameters(&mtctx->params, nbThreads);
|
||||
mtctx->cMem = cMem;
|
||||
mtctx->nbThreads = nbThreads;
|
||||
mtctx->allJobsCompleted = 1;
|
||||
mtctx->factory = POOL_create_advanced(nbThreads, 0, cMem);
|
||||
mtctx->sectionSize = 0;
|
||||
mtctx->overlapLog = ZSTDMT_OVERLAPLOG_DEFAULT;
|
||||
mtctx->factory = POOL_create(nbThreads, 0);
|
||||
mtctx->jobs = ZSTDMT_allocJobsTable(&nbJobs, cMem);
|
||||
mtctx->jobIDMask = nbJobs - 1;
|
||||
mtctx->bufPool = ZSTDMT_createBufferPool(nbThreads, cMem);
|
||||
@@ -520,35 +496,22 @@ size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx)
|
||||
+ ZSTD_sizeof_CDict(mtctx->cdictLocal);
|
||||
}
|
||||
|
||||
/* Internal only */
|
||||
size_t ZSTDMT_CCtxParam_setMTCtxParameter(
|
||||
ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value) {
|
||||
size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSDTMT_parameter parameter, unsigned value)
|
||||
{
|
||||
switch(parameter)
|
||||
{
|
||||
case ZSTDMT_p_sectionSize :
|
||||
params->jobSize = value;
|
||||
mtctx->sectionSize = value;
|
||||
return 0;
|
||||
case ZSTDMT_p_overlapSectionLog :
|
||||
DEBUGLOG(4, "ZSTDMT_p_overlapSectionLog : %u", value);
|
||||
params->overlapSizeLog = (value >= 9) ? 9 : value;
|
||||
DEBUGLOG(5, "ZSTDMT_p_overlapSectionLog : %u", value);
|
||||
mtctx->overlapLog = (value >= 9) ? 9 : value;
|
||||
return 0;
|
||||
default :
|
||||
return ERROR(parameter_unsupported);
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, unsigned value)
|
||||
{
|
||||
switch(parameter)
|
||||
{
|
||||
case ZSTDMT_p_sectionSize :
|
||||
return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value);
|
||||
case ZSTDMT_p_overlapSectionLog :
|
||||
return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value);
|
||||
default :
|
||||
return ERROR(parameter_unsupported);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------ */
|
||||
/* ===== Multi-threaded compression ===== */
|
||||
@@ -565,17 +528,17 @@ static unsigned computeNbChunks(size_t srcSize, unsigned windowLog, unsigned nbT
|
||||
return (multiplier>1) ? nbChunksLarge : nbChunksSmall;
|
||||
}
|
||||
|
||||
static size_t ZSTDMT_compress_advanced_internal(
|
||||
ZSTDMT_CCtx* mtctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
const ZSTD_CDict* cdict,
|
||||
ZSTD_CCtx_params const params)
|
||||
|
||||
size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
const ZSTD_CDict* cdict,
|
||||
ZSTD_parameters const params,
|
||||
unsigned overlapLog)
|
||||
{
|
||||
ZSTD_CCtx_params const jobParams = ZSTDMT_makeJobCCtxParams(params);
|
||||
unsigned const overlapRLog = (params.overlapSizeLog>9) ? 0 : 9-params.overlapSizeLog;
|
||||
unsigned const overlapRLog = (overlapLog>9) ? 0 : 9-overlapLog;
|
||||
size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (params.cParams.windowLog - overlapRLog);
|
||||
unsigned nbChunks = computeNbChunks(srcSize, params.cParams.windowLog, params.nbThreads);
|
||||
unsigned nbChunks = computeNbChunks(srcSize, params.cParams.windowLog, mtctx->nbThreads);
|
||||
size_t const proposedChunkSize = (srcSize + (nbChunks-1)) / nbChunks;
|
||||
size_t const avgChunkSize = ((proposedChunkSize & 0x1FFFF) < 0x7FFF) ? proposedChunkSize + 0xFFFF : proposedChunkSize; /* avoid too small last block */
|
||||
const char* const srcStart = (const char*)src;
|
||||
@@ -583,14 +546,12 @@ static size_t ZSTDMT_compress_advanced_internal(
|
||||
unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbChunks : (unsigned)(dstCapacity / ZSTD_compressBound(avgChunkSize)); /* presumes avgChunkSize >= 256 KB, which should be the case */
|
||||
size_t frameStartPos = 0, dstBufferPos = 0;
|
||||
XXH64_state_t xxh64;
|
||||
assert(jobParams.nbThreads == 0);
|
||||
assert(mtctx->cctxPool->totalCCtx == params.nbThreads);
|
||||
|
||||
DEBUGLOG(4, "nbChunks : %2u (chunkSize : %u bytes) ", nbChunks, (U32)avgChunkSize);
|
||||
if (nbChunks==1) { /* fallback to single-thread mode */
|
||||
ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0];
|
||||
if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, jobParams.fParams);
|
||||
return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, NULL, 0, jobParams);
|
||||
if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, params.fParams);
|
||||
return ZSTD_compress_advanced(cctx, dst, dstCapacity, src, srcSize, NULL, 0, params);
|
||||
}
|
||||
assert(avgChunkSize >= 256 KB); /* condition for ZSTD_compressBound(A) + ZSTD_compressBound(B) <= ZSTD_compressBound(A+B), which is required for compressWithinDst */
|
||||
ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(avgChunkSize) );
|
||||
@@ -619,7 +580,7 @@ static size_t ZSTDMT_compress_advanced_internal(
|
||||
mtctx->jobs[u].srcSize = chunkSize;
|
||||
mtctx->jobs[u].cdict = mtctx->nextJobID==0 ? cdict : NULL;
|
||||
mtctx->jobs[u].fullFrameSize = srcSize;
|
||||
mtctx->jobs[u].params = jobParams;
|
||||
mtctx->jobs[u].params = params;
|
||||
/* do not calculate checksum within sections, but write it in header for first section */
|
||||
if (u!=0) mtctx->jobs[u].params.fParams.checksumFlag = 0;
|
||||
mtctx->jobs[u].dstBuff = dstBuffer;
|
||||
@@ -690,23 +651,6 @@ static size_t ZSTDMT_compress_advanced_internal(
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
const ZSTD_CDict* cdict,
|
||||
ZSTD_parameters const params,
|
||||
unsigned overlapLog)
|
||||
{
|
||||
ZSTD_CCtx_params cctxParams = mtctx->params;
|
||||
cctxParams.cParams = params.cParams;
|
||||
cctxParams.fParams = params.fParams;
|
||||
cctxParams.overlapSizeLog = overlapLog;
|
||||
return ZSTDMT_compress_advanced_internal(mtctx,
|
||||
dst, dstCapacity,
|
||||
src, srcSize,
|
||||
cdict, cctxParams);
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
@@ -739,25 +683,23 @@ static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs)
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZSTDMT_initCStream_internal(
|
||||
ZSTDMT_CCtx* zcs,
|
||||
const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode,
|
||||
const ZSTD_CDict* cdict, ZSTD_CCtx_params params,
|
||||
unsigned long long pledgedSrcSize)
|
||||
|
||||
/** ZSTDMT_initCStream_internal() :
|
||||
* internal usage only */
|
||||
size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs,
|
||||
const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
|
||||
ZSTD_parameters params, unsigned long long pledgedSrcSize)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTDMT_initCStream_internal");
|
||||
/* 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 */
|
||||
assert(zcs->cctxPool->totalCCtx == params.nbThreads);
|
||||
|
||||
if (params.nbThreads==1) {
|
||||
ZSTD_CCtx_params const singleThreadParams = ZSTDMT_makeJobCCtxParams(params);
|
||||
if (zcs->nbThreads==1) {
|
||||
DEBUGLOG(4, "single thread mode");
|
||||
assert(singleThreadParams.nbThreads == 0);
|
||||
return ZSTD_initCStream_internal(zcs->cctxPool->cctx[0],
|
||||
dict, dictSize, cdict,
|
||||
singleThreadParams, pledgedSrcSize);
|
||||
dict, dictSize, cdict,
|
||||
params, pledgedSrcSize);
|
||||
}
|
||||
|
||||
if (zcs->allJobsCompleted == 0) { /* previous compression not correctly finished */
|
||||
@@ -772,7 +714,7 @@ size_t ZSTDMT_initCStream_internal(
|
||||
DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal);
|
||||
ZSTD_freeCDict(zcs->cdictLocal);
|
||||
zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
|
||||
ZSTD_dlm_byCopy, dictMode, /* note : a loadPrefix becomes an internal CDict */
|
||||
0 /* byRef */, ZSTD_dm_auto, /* note : a loadPrefix becomes an internal CDict */
|
||||
params.cParams, zcs->cMem);
|
||||
zcs->cdict = zcs->cdictLocal;
|
||||
if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
|
||||
@@ -783,10 +725,10 @@ size_t ZSTDMT_initCStream_internal(
|
||||
zcs->cdict = cdict;
|
||||
}
|
||||
|
||||
zcs->targetDictSize = (params.overlapSizeLog==0) ? 0 : (size_t)1 << (params.cParams.windowLog - (9 - params.overlapSizeLog));
|
||||
DEBUGLOG(4, "overlapLog : %u ", params.overlapSizeLog);
|
||||
zcs->targetDictSize = (zcs->overlapLog==0) ? 0 : (size_t)1 << (zcs->params.cParams.windowLog - (9 - zcs->overlapLog));
|
||||
DEBUGLOG(4, "overlapLog : %u ", zcs->overlapLog);
|
||||
DEBUGLOG(4, "overlap Size : %u KB", (U32)(zcs->targetDictSize>>10));
|
||||
zcs->targetSectionSize = params.jobSize ? params.jobSize : (size_t)1 << (params.cParams.windowLog + 2);
|
||||
zcs->targetSectionSize = zcs->sectionSize ? zcs->sectionSize : (size_t)1 << (zcs->params.cParams.windowLog + 2);
|
||||
zcs->targetSectionSize = MAX(ZSTDMT_SECTION_SIZE_MIN, zcs->targetSectionSize);
|
||||
zcs->targetSectionSize = MAX(zcs->targetDictSize, zcs->targetSectionSize);
|
||||
DEBUGLOG(4, "Section Size : %u KB", (U32)(zcs->targetSectionSize>>10));
|
||||
@@ -807,12 +749,8 @@ size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
|
||||
ZSTD_parameters params,
|
||||
unsigned long long pledgedSrcSize)
|
||||
{
|
||||
ZSTD_CCtx_params cctxParams = mtctx->params;
|
||||
DEBUGLOG(5, "ZSTDMT_initCStream_advanced");
|
||||
cctxParams.cParams = params.cParams;
|
||||
cctxParams.fParams = params.fParams;
|
||||
return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, ZSTD_dm_auto, NULL,
|
||||
cctxParams, pledgedSrcSize);
|
||||
return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, NULL, params, pledgedSrcSize);
|
||||
}
|
||||
|
||||
size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
|
||||
@@ -820,12 +758,11 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
|
||||
ZSTD_frameParameters fParams,
|
||||
unsigned long long pledgedSrcSize)
|
||||
{
|
||||
ZSTD_CCtx_params cctxParams = mtctx->params;
|
||||
cctxParams.cParams = ZSTD_getCParamsFromCDict(cdict);
|
||||
cctxParams.fParams = fParams;
|
||||
ZSTD_parameters params = ZSTD_getParamsFromCDict(cdict);
|
||||
if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */
|
||||
return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, ZSTD_dm_auto, cdict,
|
||||
cctxParams, pledgedSrcSize);
|
||||
params.fParams = fParams;
|
||||
return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, cdict,
|
||||
params, pledgedSrcSize);
|
||||
}
|
||||
|
||||
|
||||
@@ -833,18 +770,14 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
|
||||
* pledgedSrcSize is optional and can be zero == unknown */
|
||||
size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* zcs, unsigned long long pledgedSrcSize)
|
||||
{
|
||||
if (zcs->params.nbThreads==1)
|
||||
if (zcs->nbThreads==1)
|
||||
return ZSTD_resetCStream(zcs->cctxPool->cctx[0], pledgedSrcSize);
|
||||
return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, 0, zcs->params,
|
||||
pledgedSrcSize);
|
||||
return ZSTDMT_initCStream_internal(zcs, NULL, 0, 0, zcs->params, pledgedSrcSize);
|
||||
}
|
||||
|
||||
size_t ZSTDMT_initCStream(ZSTDMT_CCtx* zcs, int compressionLevel) {
|
||||
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0);
|
||||
ZSTD_CCtx_params cctxParams = zcs->params;
|
||||
cctxParams.cParams = params.cParams;
|
||||
cctxParams.fParams = params.fParams;
|
||||
return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, NULL, cctxParams, 0);
|
||||
return ZSTDMT_initCStream_internal(zcs, NULL, 0, NULL, params, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -988,7 +921,7 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
|
||||
/* current frame being ended. Only flush/end are allowed. Or start new frame with init */
|
||||
return ERROR(stage_wrong);
|
||||
}
|
||||
if (mtctx->params.nbThreads==1) { /* delegate to single-thread (synchronous) */
|
||||
if (mtctx->nbThreads==1) { /* delegate to single-thread (synchronous) */
|
||||
return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp);
|
||||
}
|
||||
|
||||
@@ -997,10 +930,10 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
|
||||
&& (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,
|
||||
size_t const cSize = ZSTDMT_compress_advanced(mtctx,
|
||||
(char*)output->dst + output->pos, output->size - output->pos,
|
||||
(const char*)input->src + input->pos, input->size - input->pos,
|
||||
mtctx->cdict, mtctx->params);
|
||||
mtctx->cdict, mtctx->params, mtctx->overlapLog);
|
||||
if (ZSTD_isError(cSize)) return cSize;
|
||||
input->pos = input->size;
|
||||
output->pos += cSize;
|
||||
@@ -1075,7 +1008,7 @@ static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* outp
|
||||
size_t ZSTDMT_flushStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output)
|
||||
{
|
||||
DEBUGLOG(5, "ZSTDMT_flushStream");
|
||||
if (zcs->params.nbThreads==1)
|
||||
if (zcs->nbThreads==1)
|
||||
return ZSTD_flushStream(zcs->cctxPool->cctx[0], output);
|
||||
return ZSTDMT_flushStream_internal(zcs, output, 0 /* endFrame */);
|
||||
}
|
||||
@@ -1083,7 +1016,7 @@ size_t ZSTDMT_flushStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output)
|
||||
size_t ZSTDMT_endStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTDMT_endStream");
|
||||
if (zcs->params.nbThreads==1)
|
||||
if (zcs->nbThreads==1)
|
||||
return ZSTD_endStream(zcs->cctxPool->cctx[0], output);
|
||||
return ZSTDMT_flushStream_internal(zcs, output, 1 /* endFrame */);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTDMT_COMPRESS_H
|
||||
@@ -81,19 +80,19 @@ ZSTDLIB_API size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
|
||||
ZSTD_frameParameters fparams,
|
||||
unsigned long long pledgedSrcSize); /* note : zero means empty */
|
||||
|
||||
/* ZSTDMT_parameter :
|
||||
/* ZSDTMT_parameter :
|
||||
* List of parameters that can be set using ZSTDMT_setMTCtxParameter() */
|
||||
typedef enum {
|
||||
ZSTDMT_p_sectionSize, /* size of input "section". Each section is compressed in parallel. 0 means default, which is dynamically determined within compression functions */
|
||||
ZSTDMT_p_overlapSectionLog /* Log of overlapped section; 0 == no overlap, 6(default) == use 1/8th of window, >=9 == use full window */
|
||||
} ZSTDMT_parameter;
|
||||
} ZSDTMT_parameter;
|
||||
|
||||
/* ZSTDMT_setMTCtxParameter() :
|
||||
* allow setting individual parameters, one at a time, among a list of enums defined in ZSTDMT_parameter.
|
||||
* The function must be called typically after ZSTD_createCCtx().
|
||||
* Parameters not explicitly reset by ZSTDMT_init*() remain the same in consecutive compression sessions.
|
||||
* @return : 0, or an error code (which can be tested using ZSTD_isError()) */
|
||||
ZSTDLIB_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, unsigned value);
|
||||
ZSTDLIB_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSDTMT_parameter parameter, unsigned value);
|
||||
|
||||
|
||||
/*! ZSTDMT_compressStream_generic() :
|
||||
@@ -108,22 +107,6 @@ ZSTDLIB_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
|
||||
ZSTD_EndDirective endOp);
|
||||
|
||||
|
||||
/* === Private definitions; never ever use directly === */
|
||||
|
||||
size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value);
|
||||
|
||||
size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads);
|
||||
|
||||
/*! ZSTDMT_initCStream_internal() :
|
||||
* Private use only. Init streaming operation.
|
||||
* expects params to be valid.
|
||||
* must receive dict, or cdict, or none, but not both.
|
||||
* @return : 0, or an error code */
|
||||
size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs,
|
||||
const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode,
|
||||
const ZSTD_CDict* cdict,
|
||||
ZSTD_CCtx_params params, unsigned long long pledgedSrcSize);
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -102,8 +101,7 @@ struct ZSTD_DCtx_s
|
||||
const void* dictEnd; /* end of previous segment */
|
||||
size_t expected;
|
||||
ZSTD_frameHeader fParams;
|
||||
U64 decodedSize;
|
||||
blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */
|
||||
blockType_e bType; /* used in ZSTD_decompressContinue(), to transfer blockType between header decoding and block decoding stages */
|
||||
ZSTD_dStage stage;
|
||||
U32 litEntropy;
|
||||
U32 fseEntropy;
|
||||
@@ -128,6 +126,7 @@ struct ZSTD_DCtx_s
|
||||
size_t outBuffSize;
|
||||
size_t outStart;
|
||||
size_t outEnd;
|
||||
size_t blockSize;
|
||||
size_t lhSize;
|
||||
void* legacyContext;
|
||||
U32 previousLegacyVersion;
|
||||
@@ -153,7 +152,6 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
|
||||
{
|
||||
dctx->expected = ZSTD_frameHeaderSize_prefix;
|
||||
dctx->stage = ZSTDds_getFrameHeaderSize;
|
||||
dctx->decodedSize = 0;
|
||||
dctx->previousDstEnd = NULL;
|
||||
dctx->base = NULL;
|
||||
dctx->vBase = NULL;
|
||||
@@ -173,13 +171,13 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
|
||||
static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
|
||||
{
|
||||
ZSTD_decompressBegin(dctx); /* cannot fail */
|
||||
dctx->staticSize = 0;
|
||||
dctx->staticSize = 0;
|
||||
dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
|
||||
dctx->ddict = NULL;
|
||||
dctx->ddictLocal = NULL;
|
||||
dctx->inBuff = NULL;
|
||||
dctx->inBuffSize = 0;
|
||||
dctx->outBuffSize = 0;
|
||||
dctx->ddict = NULL;
|
||||
dctx->ddictLocal = NULL;
|
||||
dctx->inBuff = NULL;
|
||||
dctx->inBuffSize = 0;
|
||||
dctx->outBuffSize= 0;
|
||||
dctx->streamStage = zdss_init;
|
||||
}
|
||||
|
||||
@@ -298,6 +296,7 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src
|
||||
memset(zfhPtr, 0, sizeof(*zfhPtr));
|
||||
zfhPtr->frameContentSize = MEM_readLE32((const char *)src + 4);
|
||||
zfhPtr->frameType = ZSTD_skippableFrame;
|
||||
zfhPtr->windowSize = 0;
|
||||
return 0;
|
||||
}
|
||||
return ERROR(prefix_unknown);
|
||||
@@ -350,7 +349,6 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src
|
||||
zfhPtr->frameType = ZSTD_frame;
|
||||
zfhPtr->frameContentSize = frameContentSize;
|
||||
zfhPtr->windowSize = windowSize;
|
||||
zfhPtr->blockSizeMax = (unsigned) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
|
||||
zfhPtr->dictID = dictID;
|
||||
zfhPtr->checksumFlag = checksumFlag;
|
||||
}
|
||||
@@ -860,10 +858,7 @@ size_t ZSTD_execSequenceLast7(BYTE* op,
|
||||
}
|
||||
|
||||
|
||||
typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e;
|
||||
|
||||
|
||||
static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets)
|
||||
static seq_t ZSTD_decodeSequence(seqState_t* seqState)
|
||||
{
|
||||
seq_t seq;
|
||||
|
||||
@@ -903,16 +898,8 @@ static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e l
|
||||
if (!ofCode)
|
||||
offset = 0;
|
||||
else {
|
||||
ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
|
||||
if (longOffsets) {
|
||||
int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN);
|
||||
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);
|
||||
} else {
|
||||
offset = OF_base[ofCode] + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
|
||||
if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
|
||||
}
|
||||
offset = OF_base[ofCode] + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
|
||||
if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
|
||||
}
|
||||
|
||||
if (ofCode <= 1) {
|
||||
@@ -1041,8 +1028,7 @@ size_t ZSTD_execSequence(BYTE* op,
|
||||
static size_t ZSTD_decompressSequences(
|
||||
ZSTD_DCtx* dctx,
|
||||
void* dst, size_t maxDstSize,
|
||||
const void* seqStart, size_t seqSize,
|
||||
const ZSTD_longOffset_e isLongOffset)
|
||||
const void* seqStart, size_t seqSize)
|
||||
{
|
||||
const BYTE* ip = (const BYTE*)seqStart;
|
||||
const BYTE* const iend = ip + seqSize;
|
||||
@@ -1077,7 +1063,7 @@ static size_t ZSTD_decompressSequences(
|
||||
|
||||
for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; ) {
|
||||
nbSeq--;
|
||||
{ seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset);
|
||||
{ seq_t const sequence = ZSTD_decodeSequence(&seqState);
|
||||
size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, base, vBase, dictEnd);
|
||||
DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize);
|
||||
if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
|
||||
@@ -1102,9 +1088,7 @@ static size_t ZSTD_decompressSequences(
|
||||
}
|
||||
|
||||
|
||||
|
||||
HINT_INLINE
|
||||
seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const longOffsets)
|
||||
FORCE_INLINE_TEMPLATE seq_t ZSTD_decodeSequenceLong_generic(seqState_t* seqState, int const longOffsets)
|
||||
{
|
||||
seq_t seq;
|
||||
|
||||
@@ -1144,7 +1128,6 @@ seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const long
|
||||
if (!ofCode)
|
||||
offset = 0;
|
||||
else {
|
||||
ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
|
||||
if (longOffsets) {
|
||||
int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN);
|
||||
offset = OF_base[ofCode] + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
|
||||
@@ -1197,12 +1180,19 @@ seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const long
|
||||
return seq;
|
||||
}
|
||||
|
||||
static seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, unsigned const windowSize) {
|
||||
if (ZSTD_highbit32(windowSize) > STREAM_ACCUMULATOR_MIN) {
|
||||
return ZSTD_decodeSequenceLong_generic(seqState, 1);
|
||||
} else {
|
||||
return ZSTD_decodeSequenceLong_generic(seqState, 0);
|
||||
}
|
||||
}
|
||||
|
||||
HINT_INLINE
|
||||
size_t ZSTD_execSequenceLong(BYTE* op,
|
||||
BYTE* const oend, seq_t sequence,
|
||||
const BYTE** litPtr, const BYTE* const litLimit,
|
||||
const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd)
|
||||
BYTE* const oend, seq_t sequence,
|
||||
const BYTE** litPtr, const BYTE* const litLimit,
|
||||
const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd)
|
||||
{
|
||||
BYTE* const oLitEnd = op + sequence.litLength;
|
||||
size_t const sequenceLength = sequence.litLength + sequence.matchLength;
|
||||
@@ -1212,9 +1202,11 @@ size_t ZSTD_execSequenceLong(BYTE* op,
|
||||
const BYTE* match = sequence.match;
|
||||
|
||||
/* check */
|
||||
#if 1
|
||||
if (oMatchEnd>oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
|
||||
if (iLitEnd > litLimit) return ERROR(corruption_detected); /* over-read beyond lit buffer */
|
||||
if (oLitEnd>oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, base, vBase, dictEnd);
|
||||
#endif
|
||||
|
||||
/* copy Literals */
|
||||
ZSTD_copy8(op, *litPtr);
|
||||
@@ -1224,6 +1216,7 @@ size_t ZSTD_execSequenceLong(BYTE* op,
|
||||
*litPtr = iLitEnd; /* update for next sequence */
|
||||
|
||||
/* copy Match */
|
||||
#if 1
|
||||
if (sequence.offset > (size_t)(oLitEnd - base)) {
|
||||
/* offset beyond prefix */
|
||||
if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected);
|
||||
@@ -1243,8 +1236,8 @@ size_t ZSTD_execSequenceLong(BYTE* op,
|
||||
return sequenceLength;
|
||||
}
|
||||
} }
|
||||
assert(op <= oend_w);
|
||||
assert(sequence.matchLength >= MINMATCH);
|
||||
/* Requirement: op <= oend_w && sequence.matchLength >= MINMATCH */
|
||||
#endif
|
||||
|
||||
/* match within prefix */
|
||||
if (sequence.offset < 8) {
|
||||
@@ -1280,8 +1273,7 @@ size_t ZSTD_execSequenceLong(BYTE* op,
|
||||
static size_t ZSTD_decompressSequencesLong(
|
||||
ZSTD_DCtx* dctx,
|
||||
void* dst, size_t maxDstSize,
|
||||
const void* seqStart, size_t seqSize,
|
||||
const ZSTD_longOffset_e isLongOffset)
|
||||
const void* seqStart, size_t seqSize)
|
||||
{
|
||||
const BYTE* ip = (const BYTE*)seqStart;
|
||||
const BYTE* const iend = ip + seqSize;
|
||||
@@ -1293,6 +1285,7 @@ static size_t ZSTD_decompressSequencesLong(
|
||||
const BYTE* const base = (const BYTE*) (dctx->base);
|
||||
const BYTE* const vBase = (const BYTE*) (dctx->vBase);
|
||||
const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
|
||||
unsigned const windowSize32 = (unsigned)dctx->fParams.windowSize;
|
||||
int nbSeq;
|
||||
|
||||
/* Build Decoding Tables */
|
||||
@@ -1322,13 +1315,13 @@ static size_t ZSTD_decompressSequencesLong(
|
||||
|
||||
/* prepare in advance */
|
||||
for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && seqNb<seqAdvance; seqNb++) {
|
||||
sequences[seqNb] = ZSTD_decodeSequenceLong(&seqState, isLongOffset);
|
||||
sequences[seqNb] = ZSTD_decodeSequenceLong(&seqState, windowSize32);
|
||||
}
|
||||
if (seqNb<seqAdvance) return ERROR(corruption_detected);
|
||||
|
||||
/* decode and decompress */
|
||||
for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && seqNb<nbSeq ; seqNb++) {
|
||||
seq_t const sequence = ZSTD_decodeSequenceLong(&seqState, isLongOffset);
|
||||
seq_t const sequence = ZSTD_decodeSequenceLong(&seqState, windowSize32);
|
||||
size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[(seqNb-ADVANCED_SEQS) & STOSEQ_MASK], &litPtr, litEnd, base, vBase, dictEnd);
|
||||
if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
|
||||
PREFETCH(sequence.match);
|
||||
@@ -1362,18 +1355,9 @@ static size_t ZSTD_decompressSequencesLong(
|
||||
|
||||
static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize, const int frame)
|
||||
const void* src, size_t srcSize)
|
||||
{ /* blockType == blockCompressed */
|
||||
const BYTE* ip = (const BYTE*)src;
|
||||
/* isLongOffset must be true if there are long offsets.
|
||||
* Offsets are long if they are larger than 2^STREAM_ACCUMULATOR_MIN.
|
||||
* We don't expect that to be the case in 64-bit mode.
|
||||
* If we are in block mode we don't know the window size, so we have to be
|
||||
* conservative.
|
||||
*/
|
||||
ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN)));
|
||||
/* We don't expect window sizes this big. */
|
||||
assert(!frame || dctx->fParams.windowSize <= (1ULL << STREAM_ACCUMULATOR_MIN_64));
|
||||
DEBUGLOG(5, "ZSTD_decompressBlock_internal");
|
||||
|
||||
if (srcSize >= ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);
|
||||
@@ -1385,9 +1369,13 @@ static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
||||
ip += litCSize;
|
||||
srcSize -= litCSize;
|
||||
}
|
||||
if (frame && dctx->fParams.windowSize > (1<<23))
|
||||
return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, isLongOffset);
|
||||
return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, isLongOffset);
|
||||
if (sizeof(size_t) > 4) /* do not enable prefetching on 32-bits x86, as it's performance detrimental */
|
||||
/* likely because of register pressure */
|
||||
/* if that's the correct cause, then 32-bits ARM should be affected differently */
|
||||
/* it would be good to test this on ARM real hardware, to see if prefetch version improves speed */
|
||||
if (dctx->fParams.windowSize > (1<<23))
|
||||
return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize);
|
||||
return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize);
|
||||
}
|
||||
|
||||
|
||||
@@ -1407,7 +1395,7 @@ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx,
|
||||
{
|
||||
size_t dSize;
|
||||
ZSTD_checkContinuity(dctx, dst);
|
||||
dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0);
|
||||
dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize);
|
||||
dctx->previousDstEnd = (char*)dst + dSize;
|
||||
return dSize;
|
||||
}
|
||||
@@ -1523,7 +1511,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
|
||||
switch(blockProperties.blockType)
|
||||
{
|
||||
case bt_compressed:
|
||||
decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize, /* frame */ 1);
|
||||
decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize);
|
||||
break;
|
||||
case bt_raw :
|
||||
decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize);
|
||||
@@ -1777,7 +1765,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||
{
|
||||
case bt_compressed:
|
||||
DEBUGLOG(5, "case bt_compressed");
|
||||
rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1);
|
||||
rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize);
|
||||
break;
|
||||
case bt_raw :
|
||||
rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize);
|
||||
@@ -1790,16 +1778,9 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||
return ERROR(corruption_detected);
|
||||
}
|
||||
if (ZSTD_isError(rSize)) return rSize;
|
||||
DEBUGLOG(5, "decoded size from block : %u", (U32)rSize);
|
||||
dctx->decodedSize += rSize;
|
||||
if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
|
||||
|
||||
if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */
|
||||
DEBUGLOG(4, "decoded size from frame : %u", (U32)dctx->decodedSize);
|
||||
if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {
|
||||
if (dctx->decodedSize != dctx->fParams.frameContentSize) {
|
||||
return ERROR(corruption_detected);
|
||||
} }
|
||||
if (dctx->fParams.checksumFlag) { /* another round for frame checksum */
|
||||
dctx->expected = 4;
|
||||
dctx->stage = ZSTDds_checkChecksum;
|
||||
@@ -1815,11 +1796,8 @@ 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);
|
||||
U32 const check32 = MEM_readLE32(src); /* srcSize == 4, guaranteed by dctx->expected */
|
||||
if (check32 != h32) return ERROR(checksum_wrong);
|
||||
dctx->expected = 0;
|
||||
dctx->stage = ZSTDds_getFrameHeaderSize;
|
||||
@@ -2006,9 +1984,9 @@ static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict* ddict)
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod)
|
||||
static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, const void* dict, size_t dictSize, unsigned byReference)
|
||||
{
|
||||
if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dict) || (!dictSize)) {
|
||||
if ((byReference) || (!dict) || (!dictSize)) {
|
||||
ddict->dictBuffer = NULL;
|
||||
ddict->dictContent = dict;
|
||||
} else {
|
||||
@@ -2027,7 +2005,7 @@ static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, const void* dict, size_
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_customMem customMem)
|
||||
ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, unsigned byReference, ZSTD_customMem customMem)
|
||||
{
|
||||
if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
|
||||
|
||||
@@ -2035,7 +2013,7 @@ ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, ZSTD_di
|
||||
if (!ddict) return NULL;
|
||||
ddict->cMem = customMem;
|
||||
|
||||
if (ZSTD_isError( ZSTD_initDDict_internal(ddict, dict, dictSize, dictLoadMethod) )) {
|
||||
if (ZSTD_isError( ZSTD_initDDict_internal(ddict, dict, dictSize, byReference) )) {
|
||||
ZSTD_freeDDict(ddict);
|
||||
return NULL;
|
||||
}
|
||||
@@ -2051,7 +2029,7 @@ ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, ZSTD_di
|
||||
ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize)
|
||||
{
|
||||
ZSTD_customMem const allocator = { NULL, NULL, NULL };
|
||||
return ZSTD_createDDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, allocator);
|
||||
return ZSTD_createDDict_advanced(dict, dictSize, 0, allocator);
|
||||
}
|
||||
|
||||
/*! ZSTD_createDDict_byReference() :
|
||||
@@ -2061,26 +2039,25 @@ ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize)
|
||||
ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize)
|
||||
{
|
||||
ZSTD_customMem const allocator = { NULL, NULL, NULL };
|
||||
return ZSTD_createDDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, allocator);
|
||||
return ZSTD_createDDict_advanced(dictBuffer, dictSize, 1, allocator);
|
||||
}
|
||||
|
||||
|
||||
ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSize,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictLoadMethod_e dictLoadMethod)
|
||||
unsigned byReference)
|
||||
{
|
||||
size_t const neededSpace =
|
||||
sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
|
||||
size_t const neededSpace = sizeof(ZSTD_DDict) + (byReference ? 0 : dictSize);
|
||||
ZSTD_DDict* const ddict = (ZSTD_DDict*)workspace;
|
||||
assert(workspace != NULL);
|
||||
assert(dict != NULL);
|
||||
if ((size_t)workspace & 7) return NULL; /* 8-aligned */
|
||||
if (workspaceSize < neededSpace) return NULL;
|
||||
if (dictLoadMethod == ZSTD_dlm_byCopy) {
|
||||
if (!byReference) {
|
||||
memcpy(ddict+1, dict, dictSize); /* local copy */
|
||||
dict = ddict+1;
|
||||
}
|
||||
if (ZSTD_isError( ZSTD_initDDict_internal(ddict, dict, dictSize, ZSTD_dlm_byRef) ))
|
||||
if (ZSTD_isError( ZSTD_initDDict_internal(ddict, dict, dictSize, 1 /* byRef */) ))
|
||||
return NULL;
|
||||
return ddict;
|
||||
}
|
||||
@@ -2098,10 +2075,10 @@ size_t ZSTD_freeDDict(ZSTD_DDict* ddict)
|
||||
|
||||
/*! ZSTD_estimateDDictSize() :
|
||||
* Estimate amount of memory that will be needed to create a dictionary for decompression.
|
||||
* Note : dictionary created by reference using ZSTD_dlm_byRef are smaller */
|
||||
size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod)
|
||||
* Note : dictionary created "byReference" are smaller */
|
||||
size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference)
|
||||
{
|
||||
return sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
|
||||
return sizeof(ZSTD_DDict) + (byReference ? 0 : dictSize);
|
||||
}
|
||||
|
||||
size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict)
|
||||
@@ -2146,7 +2123,7 @@ unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict)
|
||||
* ZSTD_getFrameHeader(), which will provide a more precise error code. */
|
||||
unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize)
|
||||
{
|
||||
ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 };
|
||||
ZSTD_frameHeader zfp = { 0, 0, ZSTD_frame, 0, 0, 0 };
|
||||
size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize);
|
||||
if (ZSTD_isError(hError)) return 0;
|
||||
return zfp.dictID;
|
||||
@@ -2253,27 +2230,17 @@ size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds)
|
||||
return ZSTD_sizeof_DCtx(zds);
|
||||
}
|
||||
|
||||
size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)
|
||||
{
|
||||
size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
|
||||
unsigned long long const neededRBSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2);
|
||||
unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);
|
||||
size_t const minRBSize = (size_t) neededSize;
|
||||
if ((unsigned long long)minRBSize != neededSize) return ERROR(frameParameter_windowTooLarge);
|
||||
return minRBSize;
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateDStreamSize(size_t windowSize)
|
||||
{
|
||||
size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
|
||||
size_t const inBuffSize = blockSize; /* no block can be larger */
|
||||
size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN);
|
||||
size_t const outBuffSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2);
|
||||
return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize;
|
||||
}
|
||||
|
||||
ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
|
||||
{
|
||||
U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable */
|
||||
U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX;
|
||||
ZSTD_frameHeader zfh;
|
||||
size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize);
|
||||
if (ZSTD_isError(err)) return err;
|
||||
@@ -2389,14 +2356,15 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_windowTooLarge);
|
||||
|
||||
/* Adapt buffer sizes to frame header instructions */
|
||||
{ size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);
|
||||
size_t const neededOutBuffSize = ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize);
|
||||
if ((zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize)) {
|
||||
size_t const bufferSize = neededInBuffSize + neededOutBuffSize;
|
||||
{ size_t const blockSize = (size_t)(MIN(zds->fParams.windowSize, ZSTD_BLOCKSIZE_MAX));
|
||||
size_t const neededOutSize = (size_t)(zds->fParams.windowSize + blockSize + WILDCOPY_OVERLENGTH * 2);
|
||||
zds->blockSize = blockSize;
|
||||
if ((zds->inBuffSize < blockSize) || (zds->outBuffSize < neededOutSize)) {
|
||||
size_t const bufferSize = blockSize + neededOutSize;
|
||||
DEBUGLOG(4, "inBuff : from %u to %u",
|
||||
(U32)zds->inBuffSize, (U32)neededInBuffSize);
|
||||
(U32)zds->inBuffSize, (U32)blockSize);
|
||||
DEBUGLOG(4, "outBuff : from %u to %u",
|
||||
(U32)zds->outBuffSize, (U32)neededOutBuffSize);
|
||||
(U32)zds->outBuffSize, (U32)neededOutSize);
|
||||
if (zds->staticSize) { /* static DCtx */
|
||||
DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize);
|
||||
assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */
|
||||
@@ -2409,9 +2377,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
zds->inBuff = (char*)ZSTD_malloc(bufferSize, zds->customMem);
|
||||
if (zds->inBuff == NULL) return ERROR(memory_allocation);
|
||||
}
|
||||
zds->inBuffSize = neededInBuffSize;
|
||||
zds->inBuffSize = blockSize;
|
||||
zds->outBuff = zds->inBuff + zds->inBuffSize;
|
||||
zds->outBuffSize = neededOutBuffSize;
|
||||
zds->outBuffSize = neededOutSize;
|
||||
} }
|
||||
zds->streamStage = zdss_read;
|
||||
/* fall-through */
|
||||
@@ -2469,13 +2437,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
zds->outStart += flushedSize;
|
||||
if (flushedSize == toFlushSize) { /* flush completed */
|
||||
zds->streamStage = zdss_read;
|
||||
if ( (zds->outBuffSize < zds->fParams.frameContentSize)
|
||||
&& (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) {
|
||||
DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)",
|
||||
(int)(zds->outBuffSize - zds->outStart),
|
||||
(U32)zds->fParams.blockSizeMax);
|
||||
if (zds->outStart + zds->blockSize > zds->outBuffSize)
|
||||
zds->outStart = zds->outEnd = 0;
|
||||
}
|
||||
break;
|
||||
} }
|
||||
/* cannot complete flush */
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* ***************************************************************
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*-*************************************
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
+8
-19
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* *****************************************************************************
|
||||
@@ -383,7 +382,7 @@ static void COVER_group(COVER_ctx_t *ctx, const void *group,
|
||||
typedef struct {
|
||||
U32 begin;
|
||||
U32 end;
|
||||
U32 score;
|
||||
double score;
|
||||
} COVER_segment_t;
|
||||
|
||||
/**
|
||||
@@ -480,16 +479,11 @@ static COVER_segment_t COVER_selectSegment(const COVER_ctx_t *ctx, U32 *freqs,
|
||||
* Check the validity of the parameters.
|
||||
* Returns non-zero if the parameters are valid and 0 otherwise.
|
||||
*/
|
||||
static int COVER_checkParameters(ZDICT_cover_params_t parameters,
|
||||
size_t maxDictSize) {
|
||||
static int COVER_checkParameters(ZDICT_cover_params_t parameters) {
|
||||
/* k and d are required parameters */
|
||||
if (parameters.d == 0 || parameters.k == 0) {
|
||||
return 0;
|
||||
}
|
||||
/* k <= maxDictSize */
|
||||
if (parameters.k > maxDictSize) {
|
||||
return 0;
|
||||
}
|
||||
/* d <= k */
|
||||
if (parameters.d > parameters.k) {
|
||||
return 0;
|
||||
@@ -628,13 +622,9 @@ static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs,
|
||||
/* Select a segment */
|
||||
COVER_segment_t segment = COVER_selectSegment(
|
||||
ctx, freqs, activeDmers, epochBegin, epochEnd, parameters);
|
||||
/* If the segment covers no dmers, then we are out of content */
|
||||
if (segment.score == 0) {
|
||||
break;
|
||||
}
|
||||
/* Trim the segment if necessary and if it is too small then we are done */
|
||||
/* Trim the segment if necessary and if it is empty then we are done */
|
||||
segmentSize = MIN(segment.end - segment.begin + parameters.d - 1, tail);
|
||||
if (segmentSize < parameters.d) {
|
||||
if (segmentSize == 0) {
|
||||
break;
|
||||
}
|
||||
/* We fill the dictionary from the back to allow the best segments to be
|
||||
@@ -658,7 +648,7 @@ ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover(
|
||||
COVER_ctx_t ctx;
|
||||
COVER_map_t activeDmers;
|
||||
/* Checks */
|
||||
if (!COVER_checkParameters(parameters, dictBufferCapacity)) {
|
||||
if (!COVER_checkParameters(parameters)) {
|
||||
DISPLAYLEVEL(1, "Cover parameters incorrect\n");
|
||||
return ERROR(GENERIC);
|
||||
}
|
||||
@@ -894,7 +884,7 @@ static void COVER_tryParameters(void *opaque) {
|
||||
goto _compressCleanup;
|
||||
}
|
||||
/* Compress each sample and sum their sizes (or error) */
|
||||
totalCompressedSize = dictBufferCapacity;
|
||||
totalCompressedSize = 0;
|
||||
for (i = 0; i < ctx->nbSamples; ++i) {
|
||||
const size_t size = ZSTD_compress_usingCDict(
|
||||
cctx, dst, dstCapacity, ctx->samples + ctx->offsets[i],
|
||||
@@ -970,7 +960,7 @@ ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
|
||||
/* Initialization */
|
||||
COVER_best_init(&best);
|
||||
/* Turn down global display level to clean up display at level 2 and below */
|
||||
g_displayLevel = displayLevel == 0 ? 0 : displayLevel - 1;
|
||||
g_displayLevel = parameters->zParams.notificationLevel - 1;
|
||||
/* Loop through d first because each new value needs a new context */
|
||||
LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n",
|
||||
kIterations);
|
||||
@@ -1004,9 +994,8 @@ ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
|
||||
data->parameters.k = k;
|
||||
data->parameters.d = d;
|
||||
data->parameters.steps = kSteps;
|
||||
data->parameters.zParams.notificationLevel = g_displayLevel;
|
||||
/* Check the parameters */
|
||||
if (!COVER_checkParameters(data->parameters, dictBufferCapacity)) {
|
||||
if (!COVER_checkParameters(data->parameters)) {
|
||||
DISPLAYLEVEL(1, "Cover parameters incorrect\n");
|
||||
free(data);
|
||||
continue;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -61,7 +60,7 @@
|
||||
|
||||
#define NOISELENGTH 32
|
||||
|
||||
static const int g_compressionLevel_default = 3;
|
||||
static const int g_compressionLevel_default = 6;
|
||||
static const U32 g_selectivity_default = 9;
|
||||
|
||||
|
||||
@@ -375,7 +374,7 @@ static int isIncluded(const void* in, const void* container, size_t length)
|
||||
return u==length;
|
||||
}
|
||||
|
||||
/*! ZDICT_tryMerge() :
|
||||
/*! ZDICT_checkMerge
|
||||
check if dictItem can be merged, do it if possible
|
||||
@return : id of destination elt, 0 if not merged
|
||||
*/
|
||||
@@ -440,8 +439,8 @@ static U32 ZDICT_tryMerge(dictItem* table, dictItem elt, U32 eltNbToSkip, const
|
||||
|
||||
static void ZDICT_removeDictItem(dictItem* table, U32 id)
|
||||
{
|
||||
/* convention : table[0].pos stores nb of elts */
|
||||
U32 const max = table[0].pos;
|
||||
/* convention : first element is nb of elts */
|
||||
U32 const max = table->pos;
|
||||
U32 u;
|
||||
if (!id) return; /* protection, should never happen */
|
||||
for (u=id; u<max-1; u++)
|
||||
@@ -704,7 +703,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize,
|
||||
memset(repOffset, 0, sizeof(repOffset));
|
||||
repOffset[1] = repOffset[4] = repOffset[8] = 1;
|
||||
memset(bestRepOffset, 0, sizeof(bestRepOffset));
|
||||
if (compressionLevel<=0) compressionLevel = g_compressionLevel_default;
|
||||
if (compressionLevel==0) compressionLevel = g_compressionLevel_default;
|
||||
params = ZSTD_getParams(compressionLevel, averageSampleSize, dictBufferSize);
|
||||
{ size_t const beginResult = ZSTD_compressBegin_advanced(esr.ref, dictBuffer, dictBufferSize, params, 0);
|
||||
if (ZSTD_isError(beginResult)) {
|
||||
@@ -1057,8 +1056,6 @@ size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity,
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.d = 8;
|
||||
params.steps = 4;
|
||||
/* Default to level 6 since no compression level information is avaialble */
|
||||
params.zParams.compressionLevel = 6;
|
||||
return ZDICT_optimizeTrainFromBuffer_cover(dictBuffer, dictBufferCapacity,
|
||||
samplesBuffer, samplesSizes,
|
||||
nbSamples, ¶ms);
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef DICTBUILDER_H_001
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# ################################################################
|
||||
# ##########################################################################
|
||||
# Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# ################################################################
|
||||
# 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.
|
||||
# ##########################################################################
|
||||
|
||||
VOID := /dev/null
|
||||
ZSTDDIR := ../include
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_LEGACY_H
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_V01_H_28739879432
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_V02_H_4174539423
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_V03_H_298734209782
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_V04_H_91868324769238
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTDv05_H
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTDv06_H
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTDv07_H_235446
|
||||
|
||||
+69
-176
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
@@ -391,9 +390,6 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output
|
||||
#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_LDM_MINMATCH_MAX 4096
|
||||
#define ZSTD_LDM_BUCKETSIZELOG_MAX 8
|
||||
|
||||
#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* for static allocation */
|
||||
#define ZSTD_FRAMEHEADERSIZE_MIN 6
|
||||
@@ -428,8 +424,6 @@ typedef struct {
|
||||
ZSTD_frameParameters fParams;
|
||||
} ZSTD_parameters;
|
||||
|
||||
typedef struct ZSTD_CCtx_params_s ZSTD_CCtx_params;
|
||||
|
||||
/*= Custom memory allocation functions */
|
||||
typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size);
|
||||
typedef void (*ZSTD_freeFunction) (void* opaque, void* address);
|
||||
@@ -499,21 +493,18 @@ 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_advanced() can provide a tighter estimation.
|
||||
* ZSTD_estimateCCtxSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||
* 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_advanced(ZSTD_compressionParameters cParams);
|
||||
ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void);
|
||||
|
||||
/*! ZSTD_estimateCStreamSize() :
|
||||
/*! ZSTD_estimate?StreamSize() :
|
||||
* 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_advanced() can provide a tighter estimation.
|
||||
* ZSTD_estimateCStreamSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||
* 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,24 +513,17 @@ 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_advanced(ZSTD_compressionParameters cParams);
|
||||
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_dictLoadMethod_e;
|
||||
|
||||
/*! ZSTD_estimate?DictSize() :
|
||||
* ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict().
|
||||
* ZSTD_estimateCStreamSize_advanced_usingCParams() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced().
|
||||
* Note : dictionary created by reference using ZSTD_dlm_byRef are smaller
|
||||
*/
|
||||
* ZSTD_estimateCStreamSize_advanced() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced().
|
||||
* Note : dictionary created "byReference" are smaller */
|
||||
ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel);
|
||||
ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod);
|
||||
ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod);
|
||||
ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference);
|
||||
ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference);
|
||||
|
||||
|
||||
/***************************************
|
||||
@@ -567,12 +551,24 @@ ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem);
|
||||
ZSTDLIB_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize);
|
||||
|
||||
|
||||
/* !!! To be deprecated !!! */
|
||||
typedef enum {
|
||||
ZSTD_p_forceWindow, /* Force back-references to remain < windowSize, even when referencing Dictionary content (default:0) */
|
||||
ZSTD_p_forceRawDict /* Force loading dictionary in "content-only" mode (no header analysis) */
|
||||
} ZSTD_CCtxParameter;
|
||||
/*! ZSTD_setCCtxParameter() :
|
||||
* Set advanced parameters, selected through enum ZSTD_CCtxParameter
|
||||
* @result : 0, or an error code (which can be tested with ZSTD_isError()) */
|
||||
ZSTDLIB_API size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value);
|
||||
|
||||
|
||||
/*! ZSTD_createCDict_byReference() :
|
||||
* Create a digested dictionary for compression
|
||||
* Dictionary content is simply referenced, and therefore stays in dictBuffer.
|
||||
* It is important that dictBuffer outlives CDict, it must remain read accessible throughout the lifetime of CDict */
|
||||
ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel);
|
||||
|
||||
|
||||
typedef enum { ZSTD_dm_auto=0, /* dictionary is "full" if it starts with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */
|
||||
ZSTD_dm_rawContent, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */
|
||||
ZSTD_dm_fullDict /* refuses to load a dictionary if it does not respect Zstandard's specification */
|
||||
@@ -580,8 +576,7 @@ typedef enum { ZSTD_dm_auto=0, /* dictionary is "full" if it starts with
|
||||
/*! ZSTD_createCDict_advanced() :
|
||||
* Create a ZSTD_CDict using external alloc and free, and customized compression parameters */
|
||||
ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize,
|
||||
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||
ZSTD_dictMode_e dictMode,
|
||||
unsigned byReference, ZSTD_dictMode_e dictMode,
|
||||
ZSTD_compressionParameters cParams,
|
||||
ZSTD_customMem customMem);
|
||||
|
||||
@@ -601,7 +596,7 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictS
|
||||
ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict(
|
||||
void* workspace, size_t workspaceSize,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode,
|
||||
unsigned byReference, ZSTD_dictMode_e dictMode,
|
||||
ZSTD_compressionParameters cParams);
|
||||
|
||||
/*! ZSTD_getCParams() :
|
||||
@@ -679,8 +674,7 @@ ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, siz
|
||||
/*! ZSTD_createDDict_advanced() :
|
||||
* Create a ZSTD_DDict using external alloc and free, optionally by reference */
|
||||
ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
|
||||
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||
ZSTD_customMem customMem);
|
||||
unsigned byReference, ZSTD_customMem customMem);
|
||||
|
||||
/*! ZSTD_initStaticDDict() :
|
||||
* Generate a digested dictionary in provided memory area.
|
||||
@@ -695,7 +689,7 @@ ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictS
|
||||
*/
|
||||
ZSTDLIB_API ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSize,
|
||||
const void* dict, size_t dictSize,
|
||||
ZSTD_dictLoadMethod_e dictLoadMethod);
|
||||
unsigned byReference);
|
||||
|
||||
/*! ZSTD_getDictID_fromDict() :
|
||||
* Provides the dictID stored within dictionary.
|
||||
@@ -730,9 +724,9 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
|
||||
ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem);
|
||||
ZSTDLIB_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */
|
||||
ZSTDLIB_API size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); /**< pledgedSrcSize must be correct, a size of 0 means unknown. for a frame size of 0 use initCStream_advanced */
|
||||
ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. Note: dict is loaded with ZSTD_dm_auto (treated as a full zstd dictionary if it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.*/
|
||||
ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. */
|
||||
ZSTDLIB_API size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize,
|
||||
ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize is optional and can be 0 (meaning unknown). note: if the contentSizeFlag is set, pledgedSrcSize == 0 means the source size is actually 0. dict is loaded with ZSTD_dm_auto and ZSTD_dlm_byCopy. */
|
||||
ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize is optional and can be 0 (meaning unknown). note: if the contentSizeFlag is set, pledgedSrcSize == 0 means the source size is actually 0 */
|
||||
ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); /**< note : cdict will just be referenced, and must outlive compression session */
|
||||
ZSTDLIB_API size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize); /**< same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
|
||||
|
||||
@@ -815,53 +809,40 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapaci
|
||||
A ZSTD_DCtx object can be re-used multiple times.
|
||||
|
||||
First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader().
|
||||
It fills a ZSTD_frameHeader structure with important information to correctly decode the frame,
|
||||
such as minimum rolling buffer size to allocate to decompress data (`windowSize`),
|
||||
and the dictionary ID in use.
|
||||
(Note : content size is optional, it may not be present. 0 means : content size unknown).
|
||||
Note that these values could be wrong, either because of data malformation, or because an attacker is spoofing deliberate false information.
|
||||
As a consequence, check that values remain within valid application range, especially `windowSize`, before allocation.
|
||||
Each application can set its own limit, depending on local restrictions.
|
||||
For extended interoperability, it is recommended to support windowSize of at least 8 MB.
|
||||
Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough.
|
||||
Data fragment must be large enough to ensure successful decoding.
|
||||
`ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough.
|
||||
`ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough.
|
||||
@result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled.
|
||||
>0 : `srcSize` is too small, please provide at least @result bytes on next attempt.
|
||||
errorCode, which can be tested using ZSTD_isError().
|
||||
|
||||
It fills a ZSTD_frameHeader structure with important information to correctly decode the frame,
|
||||
such as the dictionary ID, content size, or maximum back-reference distance (`windowSize`).
|
||||
Note that these values could be wrong, either because of data corruption, or because a 3rd party deliberately spoofs false information.
|
||||
As a consequence, check that values remain within valid application range.
|
||||
For example, do not allocate memory blindly, check that `windowSize` is within expectation.
|
||||
Each application can set its own limits, depending on local restrictions.
|
||||
For extended interoperability, it is recommended to support `windowSize` of at least 8 MB.
|
||||
|
||||
ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize` bytes.
|
||||
ZSTD_decompressContinue() is very sensitive to contiguity,
|
||||
if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place,
|
||||
or that previous contiguous segment is large enough to properly handle maximum back-reference distance.
|
||||
There are multiple ways to guarantee this condition.
|
||||
|
||||
The most memory efficient way is to use a round buffer of sufficient size.
|
||||
Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(),
|
||||
which can @return an error code if required value is too large for current system (in 32-bits mode).
|
||||
In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one,
|
||||
up to the moment there is not enough room left in the buffer to guarantee decoding another full block,
|
||||
which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`.
|
||||
At which point, decoding can resume from the beginning of the buffer.
|
||||
Note that already decoded data stored in the buffer should be flushed before being overwritten.
|
||||
|
||||
There are alternatives possible, for example using two or more buffers of size `windowSize` each, though they consume more memory.
|
||||
|
||||
Finally, if you control the compression process, you can also ignore all buffer size rules,
|
||||
as long as the encoder and decoder progress in "lock-step",
|
||||
aka use exactly the same buffer sizes, break contiguity at the same place, etc.
|
||||
|
||||
Once buffers are setup, start decompression, with ZSTD_decompressBegin().
|
||||
Start decompression, with ZSTD_decompressBegin().
|
||||
If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict().
|
||||
Alternatively, you can copy a prepared context, using ZSTD_copyDCtx().
|
||||
|
||||
Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively.
|
||||
ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue().
|
||||
ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail.
|
||||
|
||||
@result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity).
|
||||
It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item.
|
||||
@result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity).
|
||||
It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some metadata item.
|
||||
It can also be an error code, which can be tested with ZSTD_isError().
|
||||
|
||||
ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize`.
|
||||
They should preferably be located contiguously, prior to current block.
|
||||
Alternatively, a round buffer of sufficient size is also possible. Sufficient size is determined by frame parameters.
|
||||
ZSTD_decompressContinue() is very sensitive to contiguity,
|
||||
if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place,
|
||||
or that previous contiguous segment is large enough to properly handle maximum back-reference.
|
||||
|
||||
A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero.
|
||||
Context can then be reset to start a new decompression.
|
||||
|
||||
@@ -871,38 +852,36 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapaci
|
||||
== Special case : skippable frames ==
|
||||
|
||||
Skippable frames allow integration of user-defined data into a flow of concatenated frames.
|
||||
Skippable frames will be ignored (skipped) by decompressor.
|
||||
The format of skippable frames is as follows :
|
||||
Skippable frames will be ignored (skipped) by a decompressor. The format of skippable frames is as follows :
|
||||
a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F
|
||||
b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits
|
||||
c) Frame Content - any content (User Data) of length equal to Frame Size
|
||||
For skippable frames ZSTD_getFrameHeader() returns zfhPtr->frameType==ZSTD_skippableFrame.
|
||||
For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content.
|
||||
For skippable frames ZSTD_decompressContinue() always returns 0.
|
||||
For skippable frames ZSTD_getFrameHeader() returns fparamsPtr->windowLog==0 what means that a frame is skippable.
|
||||
Note : If fparamsPtr->frameContentSize==0, it is ambiguous: the frame might actually be a Zstd encoded frame with no content.
|
||||
For purposes of decompression, it is valid in both cases to skip the frame using
|
||||
ZSTD_findFrameCompressedSize to find its size in bytes.
|
||||
It also returns Frame Size as fparamsPtr->frameContentSize.
|
||||
*/
|
||||
|
||||
/*===== Buffer-less streaming decompression functions =====*/
|
||||
typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e;
|
||||
typedef struct {
|
||||
unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */
|
||||
unsigned long long frameContentSize; /* ZSTD_CONTENTSIZE_UNKNOWN means this field is not available. 0 means "empty" */
|
||||
unsigned long long windowSize; /* can be very large, up to <= frameContentSize */
|
||||
unsigned blockSizeMax;
|
||||
ZSTD_frameType_e frameType; /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */
|
||||
unsigned headerSize;
|
||||
unsigned dictID;
|
||||
unsigned checksumFlag;
|
||||
} ZSTD_frameHeader;
|
||||
ZSTDLIB_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */
|
||||
ZSTDLIB_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */
|
||||
|
||||
ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx);
|
||||
ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
|
||||
ZSTDLIB_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
|
||||
ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx);
|
||||
|
||||
ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx);
|
||||
ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||
|
||||
/* misc */
|
||||
ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx);
|
||||
typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
|
||||
ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
|
||||
|
||||
@@ -980,6 +959,12 @@ typedef enum {
|
||||
ZSTD_p_checksumFlag, /* A 32-bits checksum of content is written at end of frame (default:0) */
|
||||
ZSTD_p_dictIDFlag, /* When applicable, dictID of dictionary is provided in frame header (default:1) */
|
||||
|
||||
/* dictionary parameters (must be set before ZSTD_CCtx_loadDictionary) */
|
||||
ZSTD_p_dictMode=300, /* Select how dictionary content must be interpreted. Value must be from type ZSTD_dictMode_e.
|
||||
* default : 0==auto : dictionary will be "full" if it respects specification, otherwise it will be "rawContent" */
|
||||
ZSTD_p_refDictContent, /* Dictionary content will be referenced, instead of copied (default:0==byCopy).
|
||||
* It requires that dictionary buffer outlives its users */
|
||||
|
||||
/* multi-threading parameters */
|
||||
ZSTD_p_nbThreads=400, /* Select how many threads a compression job can spawn (default:1)
|
||||
* More threads improve speed, but also increase memory usage.
|
||||
@@ -995,35 +980,6 @@ typedef enum {
|
||||
/* advanced parameters - may not remain available after API update */
|
||||
ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize,
|
||||
* even when referencing into Dictionary content (default:0) */
|
||||
ZSTD_p_enableLongDistanceMatching=1200, /* Enable long distance matching.
|
||||
* This parameter is designed to improve the compression
|
||||
* ratio for large inputs with long distance matches.
|
||||
* This increases the memory usage as well as window size.
|
||||
* Note: setting this parameter sets all the LDM parameters
|
||||
* as well as ZSTD_p_windowLog. It should be set after
|
||||
* ZSTD_p_compressionLevel and before ZSTD_p_windowLog and
|
||||
* other LDM parameters. Setting the compression level
|
||||
* after this parameter overrides the window log, though LDM
|
||||
* will remain enabled until explicitly disabled. */
|
||||
ZSTD_p_ldmHashLog, /* Size of the table for long distance matching, as a power of 2.
|
||||
* 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). */
|
||||
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
|
||||
* and ZSTD_LDM_MINMATCH_MAX (default: 64). */
|
||||
ZSTD_p_ldmBucketSizeLog, /* Log size of each bucket in the LDM hash table for collision resolution.
|
||||
* Larger values usually improve collision resolution but may decrease
|
||||
* compression speed.
|
||||
* The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX (default: 3). */
|
||||
ZSTD_p_ldmHashEveryLog, /* Frequency of inserting/looking up entries in the LDM hash table.
|
||||
* The default is MAX(0, (windowLog - ldmHashLog)) to
|
||||
* optimize hash table usage.
|
||||
* Larger values improve compression speed. Deviating far from the
|
||||
* default value will likely result in a decrease in compression ratio.
|
||||
* Must be clamped between 0 and ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN. */
|
||||
|
||||
} ZSTD_cParameter;
|
||||
|
||||
@@ -1051,22 +1007,14 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo
|
||||
* @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_CCtx_loadDictionary_byReference() to reference dictionary
|
||||
* content instead. The dictionary buffer must then outlive its
|
||||
* users.
|
||||
* Note 1 : `dict` content will be copied internally,
|
||||
* except if ZSTD_p_refDictContent is set before loading.
|
||||
* Note 2 : Loading a dictionary involves building tables, which are dependent on compression parameters.
|
||||
* For this reason, compression parameters cannot be changed anymore after loading a dictionary.
|
||||
* It's also a CPU-heavy operation, with non-negligible impact on latency.
|
||||
* Note 3 : Dictionary will be used for all future compression jobs.
|
||||
* To return to "no-dictionary" situation, load a NULL dictionary
|
||||
* Note 5 : Use ZSTD_CCtx_loadDictionary_advanced() to select how dictionary
|
||||
* content will be interpreted.
|
||||
*/
|
||||
* To return to "no-dictionary" situation, load a NULL dictionary */
|
||||
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
|
||||
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
|
||||
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode);
|
||||
|
||||
|
||||
/*! ZSTD_CCtx_refCDict() :
|
||||
* Reference a prepared dictionary, to be used for all next compression jobs.
|
||||
@@ -1092,11 +1040,8 @@ ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
|
||||
* Note 1 : Prefix buffer is referenced. It must outlive compression job.
|
||||
* Note 2 : Referencing a prefix involves building tables, which are dependent on compression parameters.
|
||||
* It's a CPU-heavy operation, with non-negligible impact on latency.
|
||||
* Note 3 : By default, the prefix is treated as raw content
|
||||
* (ZSTD_dm_rawContent). Use ZSTD_CCtx_refPrefix_advanced() to alter
|
||||
* dictMode. */
|
||||
* Note 3 : it's possible to alter ZSTD_p_dictMode using ZSTD_CCtx_setParameter() */
|
||||
ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize);
|
||||
ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode);
|
||||
|
||||
|
||||
|
||||
@@ -1149,58 +1094,6 @@ size_t ZSTD_compress_generic_simpleArgs (
|
||||
ZSTD_EndDirective endOp);
|
||||
|
||||
|
||||
/** ZSTD_CCtx_params
|
||||
*
|
||||
* - 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_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.
|
||||
*/
|
||||
ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
|
||||
|
||||
/*! ZSTD_resetCCtxParams() :
|
||||
* Reset params to default, with the default compression level.
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params);
|
||||
|
||||
/*! ZSTD_initCCtxParams() :
|
||||
* Initializes the compression parameters of cctxParams according to
|
||||
* compression level. All other parameters are reset to their default values.
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, int compressionLevel);
|
||||
|
||||
/*! ZSTD_initCCtxParams_advanced() :
|
||||
* Initializes the compression and frame parameters of cctxParams according to
|
||||
* params. All other parameters are reset to their default values.
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_initCCtxParams_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params);
|
||||
|
||||
ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);
|
||||
|
||||
/*! ZSTD_CCtxParam_setParameter() :
|
||||
* Similar to ZSTD_CCtx_setParameter.
|
||||
* 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()).
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
||||
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
|
||||
|
||||
/**
|
||||
Block functions
|
||||
@@ -1235,7 +1128,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
||||
ZSTDLIB_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx);
|
||||
ZSTDLIB_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||
ZSTDLIB_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||
ZSTDLIB_API size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression */
|
||||
ZSTDLIB_API size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert block into `dctx` history. Useful for uncompressed blocks */
|
||||
|
||||
|
||||
#endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */
|
||||
|
||||
+22
-29
@@ -1,10 +1,12 @@
|
||||
# ################################################################
|
||||
# ##########################################################################
|
||||
# Copyright (c) 2015-present, Yann Collet, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# This Makefile is validated for Linux, macOS, *BSD, Hurd, Solaris, MSYS2 targets
|
||||
#
|
||||
# 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.
|
||||
# ##########################################################################
|
||||
# zstd : Command Line Utility, supporting gzip-like arguments
|
||||
# zstd32 : Same as zstd, but forced to compile in 32-bits mode
|
||||
@@ -66,7 +68,8 @@ endif
|
||||
else
|
||||
endif
|
||||
|
||||
ZSTDLIB_FILES := $(sort $(wildcard $(ZSTD_FILES)) $(wildcard $(ZSTDLEGACY_FILES)) $(wildcard $(ZDICT_FILES)))
|
||||
ZSTDLIB_FILES := $(wildcard $(ZSTD_FILES)) $(wildcard $(ZSTDLEGACY_FILES)) $(wildcard $(ZDICT_FILES))
|
||||
ZSTDLIB_OBJ := $(patsubst %.c,%.o,$(ZSTDLIB_FILES))
|
||||
|
||||
# Define *.exe as extension for Windows systems
|
||||
ifneq (,$(filter Windows%,$(OS)))
|
||||
@@ -209,8 +212,8 @@ zstd-decompress: $(ZSTDCOMMON_FILES) $(ZSTDDECOMP_FILES) zstdcli.c fileio.c
|
||||
zstd-compress: $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES) zstdcli.c fileio.c
|
||||
$(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT -DZSTD_NODECOMPRESS $^ -o $@$(EXT)
|
||||
|
||||
# zstd is now built with multithreading enabled y default
|
||||
zstdmt: zstd
|
||||
ln -sf zstd zstdmt
|
||||
|
||||
.PHONY: generate_res
|
||||
generate_res:
|
||||
@@ -252,35 +255,25 @@ ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD Ne
|
||||
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
|
||||
|
||||
DESTDIR ?=
|
||||
# directory variables : GNU conventions prefer lowercase
|
||||
# see https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html
|
||||
# support both lower and uppercase (BSD), use uppercase in script
|
||||
prefix ?= /usr/local
|
||||
PREFIX ?= $(prefix)
|
||||
exec_prefix ?= $(PREFIX)
|
||||
bindir ?= $(exec_prefix)/bin
|
||||
BINDIR ?= $(bindir)
|
||||
datarootdir ?= $(PREFIX)/share
|
||||
mandir ?= $(datarootdir)/man
|
||||
man1dir ?= $(mandir)/man1
|
||||
|
||||
ifneq (,$(filter $(shell uname),OpenBSD FreeBSD NetBSD DragonFly SunOS))
|
||||
MANDIR ?= $(PREFIX)/man/man1
|
||||
else
|
||||
MANDIR ?= $(man1dir)
|
||||
endif
|
||||
|
||||
ifneq (,$(filter $(shell uname),SunOS))
|
||||
INSTALL ?= ginstall
|
||||
else
|
||||
INSTALL ?= install
|
||||
endif
|
||||
|
||||
INSTALL_PROGRAM ?= $(INSTALL)
|
||||
INSTALL_SCRIPT ?= $(INSTALL_PROGRAM)
|
||||
INSTALL_DATA ?= $(INSTALL) -m 644
|
||||
INSTALL_MAN ?= $(INSTALL_DATA)
|
||||
PREFIX ?= /usr/local
|
||||
DESTDIR ?=
|
||||
BINDIR ?= $(PREFIX)/bin
|
||||
|
||||
ifneq (,$(filter $(shell uname),OpenBSD FreeBSD NetBSD DragonFly SunOS))
|
||||
MANDIR ?= $(PREFIX)/man/man1
|
||||
else
|
||||
MANDIR ?= $(PREFIX)/share/man/man1
|
||||
endif
|
||||
|
||||
INSTALL_PROGRAM ?= $(INSTALL) -m 755
|
||||
INSTALL_SCRIPT ?= $(INSTALL) -m 755
|
||||
INSTALL_MAN ?= $(INSTALL) -m 644
|
||||
|
||||
.PHONY: install
|
||||
install: zstd
|
||||
|
||||
@@ -113,7 +113,6 @@ Advanced arguments :
|
||||
-c : force write to standard output, even if it is the console
|
||||
-l : print information about zstd compressed files
|
||||
--ultra : enable levels beyond 19, up to 22 (requires more memory)
|
||||
--long : enable long distance matching (requires more memory)
|
||||
--no-dictID : don't write dictID into header (dictionary compression)
|
||||
--[no-]check : integrity check (default:enabled)
|
||||
-r : operate recursively on directories
|
||||
@@ -140,60 +139,3 @@ Benchmark arguments :
|
||||
-B# : cut file into independent blocks of size # (default: no block)
|
||||
--priority=rt : set process priority to real-time
|
||||
```
|
||||
|
||||
|
||||
#### Long distance matching mode
|
||||
The long distance matching mode, enabled with `--long`, is designed to improve
|
||||
the compression ratio for files with long matches at a large distance (up to the
|
||||
maximum window size, `128 MiB`) while still maintaining compression speed.
|
||||
|
||||
Enabling this mode sets the window size to `128 MiB` and thus increases the memory
|
||||
usage for both the compressor and decompressor. Performance in terms of speed is
|
||||
dependent on long matches being found. Compression speed may degrade if few long
|
||||
matches are found. Decompression speed usually improves when there are many long
|
||||
distance matches.
|
||||
|
||||
Below are graphs comparing the compression speed, compression ratio, and
|
||||
decompression speed with and without long distance matching on an ideal use
|
||||
case: a tar of four versions of clang (versions `3.4.1`, `3.4.2`, `3.5.0`,
|
||||
`3.5.1`) with a total size of `244889600 B`. This is an ideal use case as there
|
||||
are many long distance matches within the maximum window size of `128 MiB` (each
|
||||
version is less than `128 MiB`).
|
||||
|
||||
Compression Speed vs Ratio | Decompression Speed
|
||||
---------------------------|---------------------
|
||||
 | 
|
||||
|
||||
| Method | Compression ratio | Compression speed | Decompression speed |
|
||||
|:-------|------------------:|-------------------------:|---------------------------:|
|
||||
| `zstd -1` | `5.065` | `284.8 MB/s` | `759.3 MB/s` |
|
||||
| `zstd -5` | `5.826` | `124.9 MB/s` | `674.0 MB/s` |
|
||||
| `zstd -10` | `6.504` | `29.5 MB/s` | `771.3 MB/s` |
|
||||
| `zstd -1 --long` | `17.426` | `220.6 MB/s` | `1638.4 MB/s` |
|
||||
| `zstd -5 --long` | `19.661` | `165.5 MB/s` | `1530.6 MB/s`|
|
||||
| `zstd -10 --long`| `21.949` | `75.6 MB/s` | `1632.6 MB/s`|
|
||||
|
||||
On this file, the compression ratio improves significantly with minimal impact
|
||||
on compression speed, and the decompression speed doubles.
|
||||
|
||||
On the other extreme, compressing a file with few long distance matches (such as
|
||||
the [Silesia compression corpus]) will likely lead to a deterioration in
|
||||
compression speed (for lower levels) with minimal change in compression ratio.
|
||||
|
||||
The below table illustrates this on the [Silesia compression corpus].
|
||||
|
||||
[Silesia compression corpus]: http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia
|
||||
|
||||
| Method | Compression ratio | Compression speed | Decompression speed |
|
||||
|:-------|------------------:|-------------------------:|---------------------------:|
|
||||
| `zstd -1` | `2.878` | `231.7 MB/s` | `594.4 MB/s` |
|
||||
| `zstd -1 --long` | `2.929` | `106.5 MB/s` | `517.9 MB/s` |
|
||||
| `zstd -5` | `3.274` | `77.1 MB/s` | `464.2 MB/s` |
|
||||
| `zstd -5 --long` | `3.319` | `51.7 MB/s` | `371.9 MB/s` |
|
||||
| `zstd -10` | `3.523` | `16.4 MB/s` | `489.2 MB/s` |
|
||||
| `zstd -10 --long`| `3.566` | `16.2 MB/s` | `415.7 MB/s` |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+18
-48
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -130,31 +129,6 @@ void BMK_setNbThreads(unsigned nbThreads) {
|
||||
#endif
|
||||
g_nbThreads = nbThreads;
|
||||
}
|
||||
static U32 g_ldmFlag = 0;
|
||||
void BMK_setLdmFlag(unsigned ldmFlag) {
|
||||
g_ldmFlag = ldmFlag;
|
||||
}
|
||||
|
||||
static U32 g_ldmMinMatch = 0;
|
||||
void BMK_setLdmMinMatch(unsigned ldmMinMatch) {
|
||||
g_ldmMinMatch = ldmMinMatch;
|
||||
}
|
||||
|
||||
static U32 g_ldmHashLog = 0;
|
||||
void BMK_setLdmHashLog(unsigned ldmHashLog) {
|
||||
g_ldmHashLog = ldmHashLog;
|
||||
}
|
||||
|
||||
#define BMK_LDM_PARAM_NOTSET 9999
|
||||
static U32 g_ldmBucketSizeLog = BMK_LDM_PARAM_NOTSET;
|
||||
void BMK_setLdmBucketSizeLog(unsigned ldmBucketSizeLog) {
|
||||
g_ldmBucketSizeLog = ldmBucketSizeLog;
|
||||
}
|
||||
|
||||
static U32 g_ldmHashEveryLog = BMK_LDM_PARAM_NOTSET;
|
||||
void BMK_setLdmHashEveryLog(unsigned ldmHashEveryLog) {
|
||||
g_ldmHashEveryLog = ldmHashEveryLog;
|
||||
}
|
||||
|
||||
|
||||
/* ********************************************************
|
||||
@@ -196,6 +170,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
size_t cSize = 0;
|
||||
double ratio = 0.;
|
||||
U32 nbBlocks;
|
||||
UTIL_freq_t ticksPerSecond;
|
||||
|
||||
/* checks */
|
||||
if (!compressedBuffer || !resultBuffer || !blockTable || !ctx || !dctx)
|
||||
@@ -203,6 +178,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
|
||||
/* init */
|
||||
if (strlen(displayName)>17) displayName += strlen(displayName)-17; /* display last 17 characters */
|
||||
UTIL_initTimer(&ticksPerSecond);
|
||||
|
||||
if (g_decodeOnly) { /* benchmark only decompression : source must be already compressed */
|
||||
const char* srcPtr = (const char*)srcBuffer;
|
||||
@@ -262,15 +238,15 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
const char* const marks[NB_MARKS] = { " |", " /", " =", "\\" };
|
||||
U32 markNb = 0;
|
||||
|
||||
coolTime = UTIL_getTime();
|
||||
UTIL_getTime(&coolTime);
|
||||
DISPLAYLEVEL(2, "\r%79s\r", "");
|
||||
while (!cCompleted || !dCompleted) {
|
||||
|
||||
/* overheat protection */
|
||||
if (UTIL_clockSpanMicro(coolTime) > ACTIVEPERIOD_MICROSEC) {
|
||||
if (UTIL_clockSpanMicro(coolTime, ticksPerSecond) > ACTIVEPERIOD_MICROSEC) {
|
||||
DISPLAYLEVEL(2, "\rcooling down ... \r");
|
||||
UTIL_sleep(COOLPERIOD_SEC);
|
||||
coolTime = UTIL_getTime();
|
||||
UTIL_getTime(&coolTime);
|
||||
}
|
||||
|
||||
if (!g_decodeOnly) {
|
||||
@@ -280,8 +256,8 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
if (!cCompleted) memset(compressedBuffer, 0xE5, maxCompressedSize); /* warm up and erase result buffer */
|
||||
|
||||
UTIL_sleepMilli(1); /* give processor time to other processes */
|
||||
UTIL_waitForNextTick();
|
||||
clockStart = UTIL_getTime();
|
||||
UTIL_waitForNextTick(ticksPerSecond);
|
||||
UTIL_getTime(&clockStart);
|
||||
|
||||
if (!cCompleted) { /* still some time to do compression tests */
|
||||
U64 const clockLoop = g_nbSeconds ? TIMELOOP_MICROSEC : 1;
|
||||
@@ -290,15 +266,6 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
#ifdef ZSTD_NEWAPI
|
||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_nbThreads, g_nbThreads);
|
||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionLevel, cLevel);
|
||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_enableLongDistanceMatching, g_ldmFlag);
|
||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmMinMatch, g_ldmMinMatch);
|
||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmHashLog, g_ldmHashLog);
|
||||
if (g_ldmBucketSizeLog != BMK_LDM_PARAM_NOTSET) {
|
||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmBucketSizeLog, g_ldmBucketSizeLog);
|
||||
}
|
||||
if (g_ldmHashEveryLog != BMK_LDM_PARAM_NOTSET) {
|
||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmHashEveryLog, g_ldmHashEveryLog);
|
||||
}
|
||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_windowLog, comprParams->windowLog);
|
||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_chainLog, comprParams->chainLog);
|
||||
ZSTD_CCtx_setParameter(ctx, ZSTD_p_searchLog, comprParams->searchLog);
|
||||
@@ -317,7 +284,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
if (comprParams->searchLength) zparams.cParams.searchLength = comprParams->searchLength;
|
||||
if (comprParams->targetLength) zparams.cParams.targetLength = comprParams->targetLength;
|
||||
if (comprParams->strategy) zparams.cParams.strategy = comprParams->strategy;
|
||||
cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dm_auto, zparams.cParams, cmem);
|
||||
cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, 1 /*byRef*/, ZSTD_dm_auto, zparams.cParams, cmem);
|
||||
if (cdict==NULL) EXM_THROW(1, "ZSTD_createCDict_advanced() allocation failure");
|
||||
#endif
|
||||
do {
|
||||
@@ -362,9 +329,9 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
blockTable[blockNb].cSize = rSize;
|
||||
}
|
||||
nbLoops++;
|
||||
} while (UTIL_clockSpanMicro(clockStart) < clockLoop);
|
||||
} while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop);
|
||||
ZSTD_freeCDict(cdict);
|
||||
{ U64 const clockSpanMicro = UTIL_clockSpanMicro(clockStart);
|
||||
{ U64 const clockSpanMicro = UTIL_clockSpanMicro(clockStart, ticksPerSecond);
|
||||
if (clockSpanMicro < fastestC*nbLoops) fastestC = clockSpanMicro / nbLoops;
|
||||
totalCTime += clockSpanMicro;
|
||||
cCompleted = (totalCTime >= maxTime);
|
||||
@@ -389,14 +356,15 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
if (!dCompleted) memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */
|
||||
|
||||
UTIL_sleepMilli(1); /* give processor time to other processes */
|
||||
UTIL_waitForNextTick();
|
||||
UTIL_waitForNextTick(ticksPerSecond);
|
||||
|
||||
if (!dCompleted) {
|
||||
U64 clockLoop = g_nbSeconds ? TIMELOOP_MICROSEC : 1;
|
||||
U32 nbLoops = 0;
|
||||
UTIL_time_t clockStart;
|
||||
ZSTD_DDict* const ddict = ZSTD_createDDict(dictBuffer, dictBufferSize);
|
||||
UTIL_time_t const clockStart = UTIL_getTime();
|
||||
if (!ddict) EXM_THROW(2, "ZSTD_createDDict() allocation failure");
|
||||
UTIL_getTime(&clockStart);
|
||||
do {
|
||||
U32 blockNb;
|
||||
for (blockNb=0; blockNb<nbBlocks; blockNb++) {
|
||||
@@ -405,15 +373,17 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
blockTable[blockNb].cPtr, blockTable[blockNb].cSize,
|
||||
ddict);
|
||||
if (ZSTD_isError(regenSize)) {
|
||||
EXM_THROW(2, "ZSTD_decompress_usingDDict() failed on block %u of size %u : %s \n",
|
||||
DISPLAY("ZSTD_decompress_usingDDict() failed on block %u of size %u : %s \n",
|
||||
blockNb, (U32)blockTable[blockNb].cSize, ZSTD_getErrorName(regenSize));
|
||||
clockLoop = 0; /* force immediate test end */
|
||||
break;
|
||||
}
|
||||
blockTable[blockNb].resSize = regenSize;
|
||||
}
|
||||
nbLoops++;
|
||||
} while (UTIL_clockSpanMicro(clockStart) < clockLoop);
|
||||
} while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop);
|
||||
ZSTD_freeDDict(ddict);
|
||||
{ U64 const clockSpanMicro = UTIL_clockSpanMicro(clockStart);
|
||||
{ U64 const clockSpanMicro = UTIL_clockSpanMicro(clockStart, ticksPerSecond);
|
||||
if (clockSpanMicro < fastestD*nbLoops) fastestD = clockSpanMicro / nbLoops;
|
||||
totalDTime += clockSpanMicro;
|
||||
dCompleted = (totalDTime >= maxTime);
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -26,10 +25,5 @@ void BMK_setNbThreads(unsigned nbThreads);
|
||||
void BMK_setNotificationLevel(unsigned level);
|
||||
void BMK_setAdditionalParam(int additionalParam);
|
||||
void BMK_setDecodeOnlyMode(unsigned decodeFlag);
|
||||
void BMK_setLdmFlag(unsigned ldmFlag);
|
||||
void BMK_setLdmMinMatch(unsigned ldmMinMatch);
|
||||
void BMK_setLdmHashLog(unsigned ldmHashLog);
|
||||
void BMK_setLdmBucketSizeLog(unsigned ldmBucketSizeLog);
|
||||
void BMK_setLdmHashEveryLog(unsigned ldmHashEveryLog);
|
||||
|
||||
#endif /* BENCH_H_121279284357 */
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
+75
-118
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -14,7 +13,7 @@
|
||||
* Compiler Warnings
|
||||
****************************************/
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
||||
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
||||
#endif
|
||||
|
||||
|
||||
@@ -44,7 +43,7 @@
|
||||
#define SAMPLESIZE_MAX (128 KB)
|
||||
#define MEMMULT 11 /* rough estimation : memory cost to analyze 1 byte of sample */
|
||||
#define COVER_MEMMULT 9 /* rough estimation : memory cost to analyze 1 byte of sample */
|
||||
static const size_t g_maxMemory = (sizeof(size_t) == 4) ? (2 GB - 64 MB) : ((size_t)(512 MB) << sizeof(size_t));
|
||||
static const size_t maxMemory = (sizeof(size_t) == 4) ? (2 GB - 64 MB) : ((size_t)(512 MB) << sizeof(size_t));
|
||||
|
||||
#define NOISELENGTH 32
|
||||
|
||||
@@ -53,12 +52,13 @@ static const size_t g_maxMemory = (sizeof(size_t) == 4) ? (2 GB - 64 MB) : ((siz
|
||||
* Console display
|
||||
***************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
static int g_displayLevel = 0; /* 0 : no display; 1: errors; 2: default; 4: full information */
|
||||
|
||||
#define DISPLAYUPDATE(l, ...) if (displayLevel>=l) { \
|
||||
if ((DIB_clockSpan(g_time) > refreshRate) || (displayLevel>=4)) \
|
||||
#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
|
||||
if ((DIB_clockSpan(g_time) > refreshRate) || (g_displayLevel>=4)) \
|
||||
{ g_time = clock(); DISPLAY(__VA_ARGS__); \
|
||||
if (displayLevel>=4) fflush(stderr); } }
|
||||
if (g_displayLevel>=4) fflush(stderr); } }
|
||||
static const clock_t refreshRate = CLOCKS_PER_SEC * 2 / 10;
|
||||
static clock_t g_time = 0;
|
||||
|
||||
@@ -75,9 +75,9 @@ static clock_t DIB_clockSpan(clock_t nPrevious) { return clock() - nPrevious; }
|
||||
#define EXM_THROW(error, ...) \
|
||||
{ \
|
||||
DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \
|
||||
DISPLAY("Error %i : ", error); \
|
||||
DISPLAY(__VA_ARGS__); \
|
||||
DISPLAY("\n"); \
|
||||
DISPLAYLEVEL(1, "Error %i : ", error); \
|
||||
DISPLAYLEVEL(1, __VA_ARGS__); \
|
||||
DISPLAYLEVEL(1, "\n"); \
|
||||
exit(error); \
|
||||
}
|
||||
|
||||
@@ -97,55 +97,32 @@ const char* DiB_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCo
|
||||
* File related operations
|
||||
**********************************************************/
|
||||
/** DiB_loadFiles() :
|
||||
* load samples from files listed in fileNamesTable into buffer.
|
||||
* works even if buffer is too small to load all samples.
|
||||
* Also provides the size of each sample into sampleSizes table
|
||||
* which must be sized correctly, using DiB_fileStats().
|
||||
* @return : nb of samples effectively loaded into `buffer`
|
||||
* *bufferSizePtr is modified, it provides the amount data loaded within buffer.
|
||||
* sampleSizes is filled with the size of each sample.
|
||||
*/
|
||||
* @return : nb of files effectively loaded into `buffer` */
|
||||
static unsigned DiB_loadFiles(void* buffer, size_t* bufferSizePtr,
|
||||
size_t* sampleSizes, unsigned sstSize,
|
||||
const char** fileNamesTable, unsigned nbFiles, size_t targetChunkSize,
|
||||
unsigned displayLevel)
|
||||
size_t* fileSizes,
|
||||
const char** fileNamesTable, unsigned nbFiles)
|
||||
{
|
||||
char* const buff = (char*)buffer;
|
||||
size_t pos = 0;
|
||||
unsigned nbLoadedChunks = 0, fileIndex;
|
||||
unsigned n;
|
||||
|
||||
for (fileIndex=0; fileIndex<nbFiles; fileIndex++) {
|
||||
const char* const fileName = fileNamesTable[fileIndex];
|
||||
for (n=0; n<nbFiles; n++) {
|
||||
const char* const fileName = fileNamesTable[n];
|
||||
unsigned long long const fs64 = UTIL_getFileSize(fileName);
|
||||
unsigned long long remainingToLoad = fs64;
|
||||
U32 const nbChunks = targetChunkSize ? (U32)((fs64 + (targetChunkSize-1)) / targetChunkSize) : 1;
|
||||
U64 const chunkSize = targetChunkSize ? MIN(targetChunkSize, fs64) : fs64;
|
||||
size_t const maxChunkSize = (size_t)MIN(chunkSize, SAMPLESIZE_MAX);
|
||||
U32 cnb;
|
||||
FILE* const f = fopen(fileName, "rb");
|
||||
if (f==NULL) EXM_THROW(10, "zstd: dictBuilder: %s %s ", fileName, strerror(errno));
|
||||
DISPLAYUPDATE(2, "Loading %s... \r", fileName);
|
||||
for (cnb=0; cnb<nbChunks; cnb++) {
|
||||
size_t const toLoad = (size_t)MIN(maxChunkSize, remainingToLoad);
|
||||
if (toLoad > *bufferSizePtr-pos) break;
|
||||
{ size_t const readSize = fread(buff+pos, 1, toLoad, f);
|
||||
if (readSize != toLoad) EXM_THROW(11, "Pb reading %s", fileName);
|
||||
pos += readSize;
|
||||
sampleSizes[nbLoadedChunks++] = toLoad;
|
||||
remainingToLoad -= targetChunkSize;
|
||||
if (nbLoadedChunks == sstSize) { /* no more space left in sampleSizes table */
|
||||
fileIndex = nbFiles; /* stop there */
|
||||
break;
|
||||
}
|
||||
if (toLoad < targetChunkSize) {
|
||||
fseek(f, (long)(targetChunkSize - toLoad), SEEK_CUR);
|
||||
} } }
|
||||
fclose(f);
|
||||
}
|
||||
size_t const fileSize = (size_t) MIN(fs64, SAMPLESIZE_MAX);
|
||||
if (fileSize > *bufferSizePtr-pos) break;
|
||||
{ FILE* const f = fopen(fileName, "rb");
|
||||
if (f==NULL) EXM_THROW(10, "zstd: dictBuilder: %s %s ", fileName, strerror(errno));
|
||||
DISPLAYUPDATE(2, "Loading %s... \r", fileName);
|
||||
{ size_t const readSize = fread(buff+pos, 1, fileSize, f);
|
||||
if (readSize != fileSize) EXM_THROW(11, "Pb reading %s", fileName);
|
||||
pos += readSize; }
|
||||
fileSizes[n] = fileSize;
|
||||
fclose(f);
|
||||
} }
|
||||
DISPLAYLEVEL(2, "\r%79s\r", "");
|
||||
*bufferSizePtr = pos;
|
||||
DISPLAYLEVEL(4, "loaded : %u KB \n", (U32)(pos >> 10))
|
||||
return nbLoadedChunks;
|
||||
return n;
|
||||
}
|
||||
|
||||
#define DiB_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
||||
@@ -161,19 +138,16 @@ static U32 DiB_rand(U32* src)
|
||||
return rand32 >> 5;
|
||||
}
|
||||
|
||||
/* DiB_shuffle() :
|
||||
* shuffle a table of file names in a semi-random way
|
||||
* It improves dictionary quality by reducing "locality" impact, so if sample set is very large,
|
||||
* it will load random elements from it, instead of just the first ones. */
|
||||
static void DiB_shuffle(const char** fileNamesTable, unsigned nbFiles) {
|
||||
U32 seed = 0xFD2FB528;
|
||||
unsigned i;
|
||||
for (i = nbFiles - 1; i > 0; --i) {
|
||||
unsigned const j = DiB_rand(&seed) % (i + 1);
|
||||
const char* const tmp = fileNamesTable[j];
|
||||
fileNamesTable[j] = fileNamesTable[i];
|
||||
fileNamesTable[i] = tmp;
|
||||
}
|
||||
/* Initialize the pseudorandom number generator */
|
||||
U32 seed = 0xFD2FB528;
|
||||
unsigned i;
|
||||
for (i = nbFiles - 1; i > 0; --i) {
|
||||
unsigned const j = DiB_rand(&seed) % (i + 1);
|
||||
const char* tmp = fileNamesTable[j];
|
||||
fileNamesTable[j] = fileNamesTable[i];
|
||||
fileNamesTable[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -187,7 +161,7 @@ static size_t DiB_findMaxMem(unsigned long long requiredMem)
|
||||
|
||||
requiredMem = (((requiredMem >> 23) + 1) << 23);
|
||||
requiredMem += step;
|
||||
if (requiredMem > g_maxMemory) requiredMem = g_maxMemory;
|
||||
if (requiredMem > maxMemory) requiredMem = maxMemory;
|
||||
|
||||
while (!testmem) {
|
||||
testmem = malloc((size_t)requiredMem);
|
||||
@@ -227,33 +201,18 @@ static void DiB_saveDict(const char* dictFileName,
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
U64 totalSizeToLoad;
|
||||
unsigned oneSampleTooLarge;
|
||||
unsigned nbSamples;
|
||||
} fileStats;
|
||||
|
||||
/*! DiB_fileStats() :
|
||||
* Given a list of files, and a chunkSize (0 == no chunk, whole files)
|
||||
* provides the amount of data to be loaded and the resulting nb of samples.
|
||||
* This is useful primarily for allocation purpose => sample buffer, and sample sizes table.
|
||||
*/
|
||||
static fileStats DiB_fileStats(const char** fileNamesTable, unsigned nbFiles, size_t chunkSize, unsigned displayLevel)
|
||||
static int g_tooLargeSamples = 0;
|
||||
static U64 DiB_getTotalCappedFileSize(const char** fileNamesTable, unsigned nbFiles)
|
||||
{
|
||||
fileStats fs;
|
||||
U64 total = 0;
|
||||
unsigned n;
|
||||
memset(&fs, 0, sizeof(fs));
|
||||
for (n=0; n<nbFiles; n++) {
|
||||
U64 const fileSize = UTIL_getFileSize(fileNamesTable[n]);
|
||||
U32 const nbSamples = (U32)(chunkSize ? (fileSize + (chunkSize-1)) / chunkSize : 1);
|
||||
U64 const chunkToLoad = chunkSize ? MIN(chunkSize, fileSize) : fileSize;
|
||||
size_t const cappedChunkSize = (size_t)MIN(chunkToLoad, SAMPLESIZE_MAX);
|
||||
fs.totalSizeToLoad += cappedChunkSize * nbSamples;
|
||||
fs.oneSampleTooLarge |= (chunkSize > 2*SAMPLESIZE_MAX);
|
||||
fs.nbSamples += nbSamples;
|
||||
U64 const cappedFileSize = MIN(fileSize, SAMPLESIZE_MAX);
|
||||
total += cappedFileSize;
|
||||
g_tooLargeSamples |= (fileSize > 2*SAMPLESIZE_MAX);
|
||||
}
|
||||
DISPLAYLEVEL(4, "Preparing to load : %u KB \n", (U32)(fs.totalSizeToLoad >> 10));
|
||||
return fs;
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
@@ -270,66 +229,64 @@ size_t ZDICT_trainFromBuffer_unsafe_legacy(void* dictBuffer, size_t dictBufferCa
|
||||
|
||||
|
||||
int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize,
|
||||
const char** fileNamesTable, unsigned nbFiles, size_t chunkSize,
|
||||
const char** fileNamesTable, unsigned nbFiles,
|
||||
ZDICT_legacy_params_t *params, ZDICT_cover_params_t *coverParams,
|
||||
int optimizeCover)
|
||||
{
|
||||
unsigned const displayLevel = params ? params->zParams.notificationLevel :
|
||||
coverParams ? coverParams->zParams.notificationLevel :
|
||||
0; /* should never happen */
|
||||
void* const dictBuffer = malloc(maxDictSize);
|
||||
fileStats const fs = DiB_fileStats(fileNamesTable, nbFiles, chunkSize, displayLevel);
|
||||
size_t* const sampleSizes = (size_t*)malloc(fs.nbSamples * sizeof(size_t));
|
||||
size_t* const fileSizes = (size_t*)malloc(nbFiles * sizeof(size_t));
|
||||
unsigned long long const totalSizeToLoad = DiB_getTotalCappedFileSize(fileNamesTable, nbFiles);
|
||||
size_t const memMult = params ? MEMMULT : COVER_MEMMULT;
|
||||
size_t const maxMem = DiB_findMaxMem(fs.totalSizeToLoad * memMult) / memMult;
|
||||
size_t loadedSize = (size_t) MIN ((unsigned long long)maxMem, fs.totalSizeToLoad);
|
||||
void* const srcBuffer = malloc(loadedSize+NOISELENGTH);
|
||||
size_t const maxMem = DiB_findMaxMem(totalSizeToLoad * memMult) / memMult;
|
||||
size_t benchedSize = (size_t) MIN ((unsigned long long)maxMem, totalSizeToLoad);
|
||||
void* const srcBuffer = malloc(benchedSize+NOISELENGTH);
|
||||
int result = 0;
|
||||
|
||||
/* Checks */
|
||||
if ((!sampleSizes) || (!srcBuffer) || (!dictBuffer))
|
||||
EXM_THROW(12, "not enough memory for DiB_trainFiles"); /* should not happen */
|
||||
if (fs.oneSampleTooLarge) {
|
||||
DISPLAYLEVEL(2, "! Warning : some sample(s) are very large \n");
|
||||
DISPLAYLEVEL(2, "! Note that dictionary is only useful for small samples. \n");
|
||||
DISPLAYLEVEL(2, "! As a consequence, only the first %u bytes of each sample are loaded \n", SAMPLESIZE_MAX);
|
||||
if (params) g_displayLevel = params->zParams.notificationLevel;
|
||||
else if (coverParams) g_displayLevel = coverParams->zParams.notificationLevel;
|
||||
else EXM_THROW(13, "Neither dictionary algorith selected"); /* should not happen */
|
||||
if ((!fileSizes) || (!srcBuffer) || (!dictBuffer)) EXM_THROW(12, "not enough memory for DiB_trainFiles"); /* should not happen */
|
||||
if (g_tooLargeSamples) {
|
||||
DISPLAYLEVEL(2, "! Warning : some samples are very large \n");
|
||||
DISPLAYLEVEL(2, "! Note that dictionary is only useful for small files or beginning of large files. \n");
|
||||
DISPLAYLEVEL(2, "! As a consequence, only the first %u bytes of each file are loaded \n", SAMPLESIZE_MAX);
|
||||
}
|
||||
if (fs.nbSamples < 5) {
|
||||
if ((nbFiles < 5) || (totalSizeToLoad < 9 * (unsigned long long)maxDictSize)) {
|
||||
DISPLAYLEVEL(2, "! Warning : nb of samples too low for proper processing ! \n");
|
||||
DISPLAYLEVEL(2, "! Please provide _one file per sample_. \n");
|
||||
DISPLAYLEVEL(2, "! Alternatively, split files into fixed-size blocks representative of samples, with -B# \n");
|
||||
EXM_THROW(14, "nb of samples too low"); /* we now clearly forbid this case */
|
||||
}
|
||||
if (fs.totalSizeToLoad < (unsigned long long)(8 * maxDictSize)) {
|
||||
DISPLAYLEVEL(2, "! Warning : data size of samples too small for target dictionary size \n");
|
||||
DISPLAYLEVEL(2, "! Samples should be about 100x larger than target dictionary size \n");
|
||||
DISPLAYLEVEL(2, "! Do not concatenate samples together into a single file, \n");
|
||||
DISPLAYLEVEL(2, "! as dictBuilder will be unable to find the beginning of each sample, \n");
|
||||
DISPLAYLEVEL(2, "! resulting in poor dictionary quality. \n");
|
||||
}
|
||||
|
||||
/* init */
|
||||
if (loadedSize < fs.totalSizeToLoad)
|
||||
DISPLAYLEVEL(1, "Not enough memory; training on %u MB only...\n", (unsigned)(loadedSize >> 20));
|
||||
if (benchedSize < totalSizeToLoad)
|
||||
DISPLAYLEVEL(1, "Not enough memory; training on %u MB only...\n", (unsigned)(benchedSize >> 20));
|
||||
|
||||
/* Load input buffer */
|
||||
DISPLAYLEVEL(3, "Shuffling input files\n");
|
||||
DiB_shuffle(fileNamesTable, nbFiles);
|
||||
nbFiles = DiB_loadFiles(srcBuffer, &loadedSize, sampleSizes, fs.nbSamples, fileNamesTable, nbFiles, chunkSize, displayLevel);
|
||||
nbFiles = DiB_loadFiles(srcBuffer, &benchedSize, fileSizes, fileNamesTable, nbFiles);
|
||||
|
||||
{ size_t dictSize;
|
||||
{
|
||||
size_t dictSize;
|
||||
if (params) {
|
||||
DiB_fillNoise((char*)srcBuffer + loadedSize, NOISELENGTH); /* guard band, for end of buffer condition */
|
||||
DiB_fillNoise((char*)srcBuffer + benchedSize, NOISELENGTH); /* guard band, for end of buffer condition */
|
||||
dictSize = ZDICT_trainFromBuffer_unsafe_legacy(dictBuffer, maxDictSize,
|
||||
srcBuffer, sampleSizes, fs.nbSamples,
|
||||
srcBuffer, fileSizes, nbFiles,
|
||||
*params);
|
||||
} else if (optimizeCover) {
|
||||
dictSize = ZDICT_optimizeTrainFromBuffer_cover(dictBuffer, maxDictSize,
|
||||
srcBuffer, sampleSizes, fs.nbSamples,
|
||||
srcBuffer, fileSizes, nbFiles,
|
||||
coverParams);
|
||||
if (!ZDICT_isError(dictSize)) {
|
||||
DISPLAYLEVEL(2, "k=%u\nd=%u\nsteps=%u\n", coverParams->k, coverParams->d, coverParams->steps);
|
||||
}
|
||||
} else {
|
||||
dictSize = ZDICT_trainFromBuffer_cover(dictBuffer, maxDictSize, srcBuffer,
|
||||
sampleSizes, fs.nbSamples, *coverParams);
|
||||
dictSize =
|
||||
ZDICT_trainFromBuffer_cover(dictBuffer, maxDictSize, srcBuffer,
|
||||
fileSizes, nbFiles, *coverParams);
|
||||
}
|
||||
if (ZDICT_isError(dictSize)) {
|
||||
DISPLAYLEVEL(1, "dictionary training failed : %s \n", ZDICT_getErrorName(dictSize)); /* should not happen */
|
||||
@@ -344,7 +301,7 @@ int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize,
|
||||
/* clean up */
|
||||
_cleanup:
|
||||
free(srcBuffer);
|
||||
free(sampleSizes);
|
||||
free(dictBuffer);
|
||||
free(fileSizes);
|
||||
return result;
|
||||
}
|
||||
|
||||
+1
-2
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
/* This library is designed for a single-threaded console application.
|
||||
@@ -32,7 +31,7 @@
|
||||
@return : 0 == ok. Any other : error.
|
||||
*/
|
||||
int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize,
|
||||
const char** fileNamesTable, unsigned nbFiles, size_t chunkSize,
|
||||
const char** fileNamesTable, unsigned nbFiles,
|
||||
ZDICT_legacy_params_t *params, ZDICT_cover_params_t *coverParams,
|
||||
int optimizeCover);
|
||||
|
||||
|
||||
+13
-52
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -105,6 +104,9 @@ static clock_t g_time = 0;
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Errors
|
||||
***************************************/
|
||||
/*-*************************************
|
||||
* Debug
|
||||
***************************************/
|
||||
@@ -211,30 +213,6 @@ void FIO_setOverlapLog(unsigned overlapLog){
|
||||
DISPLAYLEVEL(2, "Setting overlapLog is useless in single-thread mode \n");
|
||||
g_overlapLog = overlapLog;
|
||||
}
|
||||
static U32 g_ldmFlag = 0;
|
||||
void FIO_setLdmFlag(unsigned ldmFlag) {
|
||||
g_ldmFlag = (ldmFlag>0);
|
||||
}
|
||||
static U32 g_ldmHashLog = 0;
|
||||
void FIO_setLdmHashLog(unsigned ldmHashLog) {
|
||||
g_ldmHashLog = ldmHashLog;
|
||||
}
|
||||
static U32 g_ldmMinMatch = 0;
|
||||
void FIO_setLdmMinMatch(unsigned ldmMinMatch) {
|
||||
g_ldmMinMatch = ldmMinMatch;
|
||||
}
|
||||
|
||||
#define FIO_LDM_PARAM_NOTSET 9999
|
||||
static U32 g_ldmBucketSizeLog = FIO_LDM_PARAM_NOTSET;
|
||||
void FIO_setLdmBucketSizeLog(unsigned ldmBucketSizeLog) {
|
||||
g_ldmBucketSizeLog = ldmBucketSizeLog;
|
||||
}
|
||||
|
||||
static U32 g_ldmHashEveryLog = FIO_LDM_PARAM_NOTSET;
|
||||
void FIO_setLdmHashEveryLog(unsigned ldmHashEveryLog) {
|
||||
g_ldmHashEveryLog = ldmHashEveryLog;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-*************************************
|
||||
@@ -420,20 +398,8 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
|
||||
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) );
|
||||
/* compression level */
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionLevel, cLevel) );
|
||||
/* long distance matching */
|
||||
CHECK( ZSTD_CCtx_setParameter(
|
||||
ress.cctx, ZSTD_p_enableLongDistanceMatching, g_ldmFlag) );
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmHashLog, g_ldmHashLog) );
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmMinMatch, g_ldmMinMatch) );
|
||||
if (g_ldmBucketSizeLog != FIO_LDM_PARAM_NOTSET) {
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmBucketSizeLog, g_ldmBucketSizeLog) );
|
||||
}
|
||||
if (g_ldmHashEveryLog != FIO_LDM_PARAM_NOTSET) {
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmHashEveryLog, g_ldmHashEveryLog) );
|
||||
}
|
||||
/* compression parameters */
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionLevel, cLevel) );
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_windowLog, comprParams->windowLog) );
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_chainLog, comprParams->chainLog) );
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_hashLog, comprParams->hashLog) );
|
||||
@@ -1020,8 +986,8 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile
|
||||
***************************************************************************/
|
||||
typedef struct {
|
||||
void* srcBuffer;
|
||||
size_t srcBufferSize;
|
||||
size_t srcBufferLoaded;
|
||||
size_t srcBufferSize;
|
||||
void* dstBuffer;
|
||||
size_t dstBufferSize;
|
||||
ZSTD_DStream* dctx;
|
||||
@@ -1557,11 +1523,11 @@ static int FIO_decompressSrcFile(dRess_t ress, const char* dstFileName, const ch
|
||||
|
||||
/* Close file */
|
||||
if (fclose(srcFile)) {
|
||||
DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno)); /* error should not happen */
|
||||
DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno)); /* error should never happen */
|
||||
return 1;
|
||||
}
|
||||
if ( g_removeSrcFile /* --rm */
|
||||
&& (result==0) /* decompression successful */
|
||||
&& (result==0) /* decompression successful */
|
||||
&& strcmp(srcFileName, stdinmark) ) /* not stdin */ {
|
||||
if (remove(srcFileName)) {
|
||||
/* failed to remove src file */
|
||||
@@ -1587,8 +1553,7 @@ static int FIO_decompressDstFile(dRess_t ress,
|
||||
ress.dstFile = FIO_openDstFile(dstFileName);
|
||||
if (ress.dstFile==0) return 1;
|
||||
|
||||
if ( strcmp(srcFileName, stdinmark)
|
||||
&& UTIL_getFileStat(srcFileName, &statbuf) )
|
||||
if (strcmp (srcFileName, stdinmark) && UTIL_getFileStat(srcFileName, &statbuf))
|
||||
stat_result = 1;
|
||||
result = FIO_decompressSrcFile(ress, dstFileName, srcFileName);
|
||||
|
||||
@@ -1598,15 +1563,11 @@ static int FIO_decompressDstFile(dRess_t ress,
|
||||
}
|
||||
|
||||
if ( (result != 0) /* operation failure */
|
||||
&& strcmp(dstFileName, nulmark) /* special case : don't remove() /dev/null (#316) */
|
||||
&& strcmp(dstFileName, stdoutmark) ) /* special case : don't remove() stdout */
|
||||
remove(dstFileName); /* remove decompression artefact; note don't do anything special if remove() fails */
|
||||
else { /* operation success */
|
||||
if ( strcmp(dstFileName, stdoutmark) /* special case : don't chmod stdout */
|
||||
&& strcmp(dstFileName, nulmark) /* special case : don't chmod /dev/null */
|
||||
&& stat_result ) /* file permissions correctly extracted from src */
|
||||
UTIL_setFileStat(dstFileName, &statbuf); /* transfer file permissions from src into dst */
|
||||
}
|
||||
&& strcmp(dstFileName, nulmark) /* special case : don't remove() /dev/null (#316) */
|
||||
&& remove(dstFileName) /* remove artefact */ )
|
||||
result=1; /* don't do anything special if remove() fails */
|
||||
else if (strcmp (dstFileName, stdoutmark) && stat_result)
|
||||
UTIL_setFileStat(dstFileName, &statbuf);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -57,11 +56,6 @@ void FIO_setMemLimit(unsigned memLimit);
|
||||
void FIO_setNbThreads(unsigned nbThreads);
|
||||
void FIO_setBlockSize(unsigned blockSize);
|
||||
void FIO_setOverlapLog(unsigned overlapLog);
|
||||
void FIO_setLdmFlag(unsigned ldmFlag);
|
||||
void FIO_setLdmHashLog(unsigned ldmHashLog);
|
||||
void FIO_setLdmMinMatch(unsigned ldmMinMatch);
|
||||
void FIO_setLdmBucketSizeLog(unsigned ldmBucketSizeLog);
|
||||
void FIO_setLdmHashEveryLog(unsigned ldmHashEveryLog);
|
||||
|
||||
|
||||
/*-*************************************
|
||||
|
||||
+1
-2
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef PLATFORM_H_MODULE
|
||||
|
||||
+44
-111
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef UTIL_H_MODULE
|
||||
@@ -106,128 +105,58 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*-****************************************
|
||||
* Console log
|
||||
******************************************/
|
||||
static int g_utilDisplayLevel;
|
||||
#define UTIL_DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define UTIL_DISPLAYLEVEL(l, ...) { if (g_utilDisplayLevel>=l) { UTIL_DISPLAY(__VA_ARGS__); } }
|
||||
|
||||
|
||||
/*-****************************************
|
||||
* Time functions
|
||||
******************************************/
|
||||
#if defined(_WIN32) /* Windows */
|
||||
typedef LARGE_INTEGER UTIL_time_t;
|
||||
UTIL_STATIC UTIL_time_t UTIL_getTime(void) { UTIL_time_t x; QueryPerformanceCounter(&x); return x; }
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd)
|
||||
{
|
||||
static LARGE_INTEGER ticksPerSecond;
|
||||
static int init = 0;
|
||||
if (!init) {
|
||||
if (!QueryPerformanceFrequency(&ticksPerSecond))
|
||||
UTIL_DISPLAYLEVEL(1, "ERROR: QueryPerformanceFrequency() failure\n");
|
||||
init = 1;
|
||||
}
|
||||
return 1000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart;
|
||||
}
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd)
|
||||
{
|
||||
static LARGE_INTEGER ticksPerSecond;
|
||||
static int init = 0;
|
||||
if (!init) {
|
||||
if (!QueryPerformanceFrequency(&ticksPerSecond))
|
||||
UTIL_DISPLAYLEVEL(1, "ERROR: QueryPerformanceFrequency() failure\n");
|
||||
init = 1;
|
||||
}
|
||||
return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart;
|
||||
}
|
||||
typedef LARGE_INTEGER UTIL_freq_t;
|
||||
typedef LARGE_INTEGER UTIL_time_t;
|
||||
UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { if (!QueryPerformanceFrequency(ticksPerSecond)) fprintf(stderr, "ERROR: QueryPerformance not present\n"); }
|
||||
UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { QueryPerformanceCounter(x); }
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; }
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; }
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
#include <mach/mach_time.h>
|
||||
typedef U64 UTIL_time_t;
|
||||
UTIL_STATIC UTIL_time_t UTIL_getTime(void) { return mach_absolute_time(); }
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd)
|
||||
{
|
||||
static mach_timebase_info_data_t rate;
|
||||
static int init = 0;
|
||||
if (!init) {
|
||||
mach_timebase_info(&rate);
|
||||
init = 1;
|
||||
}
|
||||
return (((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom))/1000ULL;
|
||||
}
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd)
|
||||
{
|
||||
static mach_timebase_info_data_t rate;
|
||||
static int init = 0;
|
||||
if (!init) {
|
||||
mach_timebase_info(&rate);
|
||||
init = 1;
|
||||
}
|
||||
return ((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom);
|
||||
}
|
||||
#include <mach/mach_time.h>
|
||||
typedef mach_timebase_info_data_t UTIL_freq_t;
|
||||
typedef U64 UTIL_time_t;
|
||||
UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* rate) { mach_timebase_info(rate); }
|
||||
UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { *x = mach_absolute_time(); }
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t rate, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return (((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom))/1000ULL; }
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t rate, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return ((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom); }
|
||||
#elif (PLATFORM_POSIX_VERSION >= 200112L)
|
||||
#include <time.h>
|
||||
typedef struct timespec UTIL_freq_t;
|
||||
typedef struct timespec UTIL_time_t;
|
||||
UTIL_STATIC UTIL_time_t UTIL_getTime(void)
|
||||
{
|
||||
UTIL_time_t time;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &time))
|
||||
UTIL_DISPLAYLEVEL(1, "ERROR: Failed to get time\n"); /* we could also exit() */
|
||||
return time;
|
||||
}
|
||||
UTIL_STATIC UTIL_time_t UTIL_getSpanTime(UTIL_time_t begin, UTIL_time_t end)
|
||||
{
|
||||
UTIL_time_t diff;
|
||||
if (end.tv_nsec < begin.tv_nsec) {
|
||||
diff.tv_sec = (end.tv_sec - 1) - begin.tv_sec;
|
||||
diff.tv_nsec = (end.tv_nsec + 1000000000ULL) - begin.tv_nsec;
|
||||
} else {
|
||||
diff.tv_sec = end.tv_sec - begin.tv_sec;
|
||||
diff.tv_nsec = end.tv_nsec - begin.tv_nsec;
|
||||
}
|
||||
return diff;
|
||||
}
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t begin, UTIL_time_t end)
|
||||
{
|
||||
UTIL_time_t const diff = UTIL_getSpanTime(begin, end);
|
||||
U64 micro = 0;
|
||||
micro += 1000000ULL * diff.tv_sec;
|
||||
micro += diff.tv_nsec / 1000ULL;
|
||||
return micro;
|
||||
}
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t begin, UTIL_time_t end)
|
||||
{
|
||||
UTIL_time_t const diff = UTIL_getSpanTime(begin, end);
|
||||
U64 nano = 0;
|
||||
nano += 1000000000ULL * diff.tv_sec;
|
||||
nano += diff.tv_nsec;
|
||||
return nano;
|
||||
}
|
||||
#include <sys/times.h> /* times */
|
||||
typedef U64 UTIL_freq_t;
|
||||
typedef U64 UTIL_time_t;
|
||||
UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { *ticksPerSecond=sysconf(_SC_CLK_TCK); }
|
||||
UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { struct tms junk; clock_t newTicks = (clock_t) times(&junk); (void)junk; *x = (UTIL_time_t)newTicks; }
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL * (clockEnd - clockStart) / ticksPerSecond; }
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL * (clockEnd - clockStart) / ticksPerSecond; }
|
||||
#else /* relies on standard C (note : clock_t measurements can be wrong when using multi-threading) */
|
||||
typedef clock_t UTIL_time_t;
|
||||
UTIL_STATIC UTIL_time_t UTIL_getTime(void) { return clock(); }
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; }
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; }
|
||||
typedef clock_t UTIL_freq_t;
|
||||
typedef clock_t UTIL_time_t;
|
||||
UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { *ticksPerSecond=0; }
|
||||
UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { *x = clock(); }
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { (void)ticksPerSecond; return 1000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; }
|
||||
UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { (void)ticksPerSecond; return 1000000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; }
|
||||
#endif
|
||||
|
||||
|
||||
/* returns time span in microseconds */
|
||||
UTIL_STATIC U64 UTIL_clockSpanMicro( UTIL_time_t clockStart )
|
||||
UTIL_STATIC U64 UTIL_clockSpanMicro( UTIL_time_t clockStart, UTIL_freq_t ticksPerSecond )
|
||||
{
|
||||
UTIL_time_t const clockEnd = UTIL_getTime();
|
||||
return UTIL_getSpanTimeMicro(clockStart, clockEnd);
|
||||
UTIL_time_t clockEnd;
|
||||
UTIL_getTime(&clockEnd);
|
||||
return UTIL_getSpanTimeMicro(ticksPerSecond, clockStart, clockEnd);
|
||||
}
|
||||
|
||||
|
||||
UTIL_STATIC void UTIL_waitForNextTick(void)
|
||||
UTIL_STATIC void UTIL_waitForNextTick(UTIL_freq_t ticksPerSecond)
|
||||
{
|
||||
UTIL_time_t const clockStart = UTIL_getTime();
|
||||
UTIL_time_t clockEnd;
|
||||
UTIL_time_t clockStart, clockEnd;
|
||||
UTIL_getTime(&clockStart);
|
||||
do {
|
||||
clockEnd = UTIL_getTime();
|
||||
} while (UTIL_getSpanTimeNano(clockStart, clockEnd) == 0);
|
||||
UTIL_getTime(&clockEnd);
|
||||
} while (UTIL_getSpanTimeNano(ticksPerSecond, clockStart, clockEnd) == 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -355,6 +284,10 @@ UTIL_STATIC void *UTIL_realloc(void *ptr, size_t size)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int g_utilDisplayLevel;
|
||||
#define UTIL_DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define UTIL_DISPLAYLEVEL(l, ...) { if (g_utilDisplayLevel>=l) { UTIL_DISPLAY(__VA_ARGS__); } }
|
||||
|
||||
#ifdef _WIN32
|
||||
# define UTIL_HAS_CREATEFILELIST
|
||||
|
||||
@@ -376,7 +309,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_
|
||||
|
||||
hFile=FindFirstFileA(path, &cFile);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s'\n", dirName);
|
||||
fprintf(stderr, "Cannot open directory '%s'\n", dirName);
|
||||
return 0;
|
||||
}
|
||||
free(path);
|
||||
@@ -430,7 +363,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_
|
||||
int dirLength, fnameLength, pathLength, nbFiles = 0;
|
||||
|
||||
if (!(dir = opendir(dirName))) {
|
||||
UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s': %s\n", dirName, strerror(errno));
|
||||
fprintf(stderr, "Cannot open directory '%s': %s\n", dirName, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -475,7 +408,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_
|
||||
}
|
||||
|
||||
if (errno != 0) {
|
||||
UTIL_DISPLAYLEVEL(1, "readdir(%s) error: %s\n", dirName, strerror(errno));
|
||||
fprintf(stderr, "readdir(%s) error: %s\n", dirName, strerror(errno));
|
||||
free(*bufStart);
|
||||
*bufStart = NULL;
|
||||
}
|
||||
@@ -488,7 +421,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_
|
||||
UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks)
|
||||
{
|
||||
(void)bufStart; (void)bufEnd; (void)pos;
|
||||
UTIL_DISPLAYLEVEL(1, "Directory %s ignored (compiled without _WIN32 or _POSIX_C_SOURCE)\n", dirName);
|
||||
fprintf(stderr, "Directory %s ignored (compiled without _WIN32 or _POSIX_C_SOURCE)\n", dirName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-57
@@ -1,5 +1,5 @@
|
||||
.
|
||||
.TH "ZSTD" "1" "September 2017" "zstd 1.3.1" "User Commands"
|
||||
.TH "ZSTD" "1" "August 2017" "zstd 1.3.1" "User Commands"
|
||||
.
|
||||
.SH "NAME"
|
||||
\fBzstd\fR \- zstd, zstdmt, unzstd, zstdcat \- Compress or decompress \.zst files
|
||||
@@ -104,10 +104,6 @@ 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)\.
|
||||
.
|
||||
.TP
|
||||
\fB\-T#\fR, \fB\-\-threads=#\fR
|
||||
Compress using \fB#\fR threads (default: 1)\. If \fB#\fR is 0, attempt to detect and use the number of physical CPU cores\. In all cases, the nb of threads is capped to ZSTDMT_NBTHREADS_MAX==256\. This modifier does nothing if \fBzstd\fR is compiled without multithread support\.
|
||||
.
|
||||
@@ -326,58 +322,6 @@ Determine \fBoverlapSize\fR, amount of data reloaded from previous job\. This pa
|
||||
.IP
|
||||
The minimum \fIovlog\fR is 0, and the maximum is 9\. 0 means "no overlap", hence completely independent jobs\. 9 means "full overlap", meaning up to \fBwindowSize\fR is reloaded from previous job\. Reducing \fIovlog\fR by 1 reduces the amount of reload by a factor 2\. Default \fIovlog\fR is 6, which means "reload \fBwindowSize / 8\fR"\. Exception : the maximum compression level (22) has a default \fIovlog\fR of 9\.
|
||||
.
|
||||
.TP
|
||||
\fBldmHashLog\fR=\fIldmhlog\fR, \fBldmhlog\fR=\fIldmhlog\fR
|
||||
Specify the maximum size for a hash table used for long distance matching\.
|
||||
.
|
||||
.IP
|
||||
This option is ignored unless long distance matching is enabled\.
|
||||
.
|
||||
.IP
|
||||
Bigger hash tables usually improve compression ratio at the expense of more memory during compression and a decrease in compression speed\.
|
||||
.
|
||||
.IP
|
||||
The minimum \fIldmhlog\fR is 6 and the maximum is 26 (default: 20)\.
|
||||
.
|
||||
.TP
|
||||
\fBldmSearchLength\fR=\fIldmslen\fR, \fBldmSlen\fR=\fIldmslen\fR
|
||||
Specify the minimum searched length of a match for long distance matching\.
|
||||
.
|
||||
.IP
|
||||
This option is ignored unless long distance matching is enabled\.
|
||||
.
|
||||
.IP
|
||||
Larger/very small values usually decrease compression ratio\.
|
||||
.
|
||||
.IP
|
||||
The minumum \fIldmslen\fR is 4 and the maximum is 4096 (default: 64)\.
|
||||
.
|
||||
.TP
|
||||
\fBldmBucketSizeLog\fR=\fIldmblog\fR, \fBldmblog\fR=\fIldmblog\fR
|
||||
Specify the size of each bucket for the hash table used for long distance matching\.
|
||||
.
|
||||
.IP
|
||||
This option is ignored unless long distance matching is enabled\.
|
||||
.
|
||||
.IP
|
||||
Larger bucket sizes improve collision resolution but decrease compression speed\.
|
||||
.
|
||||
.IP
|
||||
The minimum \fIldmblog\fR is 0 and the maximum is 8 (default: 3)\.
|
||||
.
|
||||
.TP
|
||||
\fBldmHashEveryLog\fR=\fIldmhevery\fR, \fBldmhevery\fR=\fIldmhevery\fR
|
||||
Specify the frequency of inserting entries into the long distance matching hash table\.
|
||||
.
|
||||
.IP
|
||||
This option is ignored unless long distance matching is enabled\.
|
||||
.
|
||||
.IP
|
||||
Larger values will improve compression speed\. Deviating far from the default value will likely result in a decrease in compression ratio\.
|
||||
.
|
||||
.IP
|
||||
The default value is \fBwlog \- ldmhlog\fR\.
|
||||
.
|
||||
.SS "\-B#:"
|
||||
Select the size of each compression job\. This parameter is available only when multi\-threading is enabled\. Default value is \fB4 * windowSize\fR, which means it varies depending on compression level\. \fB\-B#\fR makes it possible to select a custom value\. Note that job size must respect a minimum value which is enforced transparently\. This minimum is either 1 MB, or \fBoverlapSize\fR, whichever is largest\.
|
||||
.
|
||||
|
||||
@@ -105,12 +105,6 @@ 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.
|
||||
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).
|
||||
* `-T#`, `--threads=#`:
|
||||
Compress using `#` threads (default: 1).
|
||||
If `#` is 0, attempt to detect and use the number of physical CPU cores.
|
||||
@@ -184,8 +178,6 @@ Typical gains range from 10% (at 64KB) to x5 better (at <1KB).
|
||||
Dictionary saved into `file` (default name: dictionary).
|
||||
* `--maxdict=#`:
|
||||
Limit dictionary to specified size (default: 112640).
|
||||
* `-B#`:
|
||||
Split input files in blocks of size # (default: no split)
|
||||
* `--dictID=#`:
|
||||
A dictionary ID is a locally unique ID that a decoder can use to verify it is
|
||||
using the right dictionary.
|
||||
@@ -335,47 +327,6 @@ The list of available _options_:
|
||||
Default _ovlog_ is 6, which means "reload `windowSize / 8`".
|
||||
Exception : the maximum compression level (22) has a default _ovlog_ of 9.
|
||||
|
||||
- `ldmHashLog`=_ldmhlog_, `ldmhlog`=_ldmhlog_:
|
||||
Specify the maximum size for a hash table used for long distance matching.
|
||||
|
||||
This option is ignored unless long distance matching is enabled.
|
||||
|
||||
Bigger hash tables usually improve compression ratio at the expense of more
|
||||
memory during compression and a decrease in compression speed.
|
||||
|
||||
The minimum _ldmhlog_ is 6 and the maximum is 26 (default: 20).
|
||||
|
||||
- `ldmSearchLength`=_ldmslen_, `ldmslen`=_ldmslen_:
|
||||
Specify the minimum searched length of a match for long distance matching.
|
||||
|
||||
This option is ignored unless long distance matching is enabled.
|
||||
|
||||
Larger/very small values usually decrease compression ratio.
|
||||
|
||||
The minumum _ldmslen_ is 4 and the maximum is 4096 (default: 64).
|
||||
|
||||
- `ldmBucketSizeLog`=_ldmblog_, `ldmblog`=_ldmblog_:
|
||||
Specify the size of each bucket for the hash table used for long distance
|
||||
matching.
|
||||
|
||||
This option is ignored unless long distance matching is enabled.
|
||||
|
||||
Larger bucket sizes improve collision resolution but decrease compression
|
||||
speed.
|
||||
|
||||
The minimum _ldmblog_ is 0 and the maximum is 8 (default: 3).
|
||||
|
||||
- `ldmHashEveryLog`=_ldmhevery_, `ldmhevery`=_ldmhevery_:
|
||||
Specify the frequency of inserting entries into the long distance matching
|
||||
hash table.
|
||||
|
||||
This option is ignored unless long distance matching is enabled.
|
||||
|
||||
Larger values will improve compression speed. Deviating far from the
|
||||
default value will likely result in a decrease in compression ratio.
|
||||
|
||||
The default value is `wlog - ldmhlog`.
|
||||
|
||||
### -B#:
|
||||
Select the size of each compression job.
|
||||
This parameter is available only when multi-threading is enabled.
|
||||
|
||||
+4
-36
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -73,12 +72,7 @@ static const unsigned g_defaultMaxDictSize = 110 KB;
|
||||
static const int g_defaultDictCLevel = 3;
|
||||
static const unsigned g_defaultSelectivityLevel = 9;
|
||||
#define OVERLAP_LOG_DEFAULT 9999
|
||||
#define LDM_PARAM_DEFAULT 9999 /* Default for parameters where 0 is valid */
|
||||
static U32 g_overlapLog = OVERLAP_LOG_DEFAULT;
|
||||
static U32 g_ldmHashLog = 0;
|
||||
static U32 g_ldmMinMatch = 0;
|
||||
static U32 g_ldmHashEveryLog = LDM_PARAM_DEFAULT;
|
||||
static U32 g_ldmBucketSizeLog = LDM_PARAM_DEFAULT;
|
||||
|
||||
|
||||
/*-************************************
|
||||
@@ -129,7 +123,6 @@ 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");
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
DISPLAY( " -T# : use # threads for compression (default:1) \n");
|
||||
DISPLAY( " -B# : select size of each job (default:0==automatic) \n");
|
||||
@@ -311,10 +304,6 @@ static unsigned parseCompressionParameters(const char* stringPtr, ZSTD_compressi
|
||||
if (longCommandWArg(&stringPtr, "targetLength=") || longCommandWArg(&stringPtr, "tlen=")) { params->targetLength = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
|
||||
if (longCommandWArg(&stringPtr, "strategy=") || longCommandWArg(&stringPtr, "strat=")) { params->strategy = (ZSTD_strategy)(readU32FromChar(&stringPtr)); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
|
||||
if (longCommandWArg(&stringPtr, "overlapLog=") || longCommandWArg(&stringPtr, "ovlog=")) { g_overlapLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
|
||||
if (longCommandWArg(&stringPtr, "ldmHashLog=") || longCommandWArg(&stringPtr, "ldmhlog=")) { g_ldmHashLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
|
||||
if (longCommandWArg(&stringPtr, "ldmSearchLength=") || longCommandWArg(&stringPtr, "ldmslen=")) { g_ldmMinMatch = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
|
||||
if (longCommandWArg(&stringPtr, "ldmBucketSizeLog=") || longCommandWArg(&stringPtr, "ldmblog=")) { g_ldmBucketSizeLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
|
||||
if (longCommandWArg(&stringPtr, "ldmHashEveryLog=") || longCommandWArg(&stringPtr, "ldmhevery=")) { g_ldmHashEveryLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -373,8 +362,7 @@ int main(int argCount, const char* argv[])
|
||||
ultra=0,
|
||||
lastCommand = 0,
|
||||
nbThreads = 1,
|
||||
setRealTimePrio = 0,
|
||||
ldmFlag = 0;
|
||||
setRealTimePrio = 0;
|
||||
unsigned bench_nbSeconds = 3; /* would be better if this value was synchronized from bench */
|
||||
size_t blockSize = 0;
|
||||
zstd_operation_mode operation = zom_compress;
|
||||
@@ -406,7 +394,7 @@ int main(int argCount, const char* argv[])
|
||||
/* 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 */
|
||||
(void)ultra; (void)cLevel; (void)ldmFlag; /* not used when ZSTD_NOCOMPRESS set */
|
||||
(void)ultra; (void)cLevel; /* not used when ZSTD_NOCOMPRESS set */
|
||||
(void)memLimit; /* not used when ZSTD_NODECOMPRESS set */
|
||||
if (filenameTable==NULL) { DISPLAY("zstd: %s \n", strerror(errno)); exit(1); }
|
||||
filenameTable[0] = stdinmark;
|
||||
@@ -459,7 +447,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; }
|
||||
@@ -733,15 +720,6 @@ int main(int argCount, const char* argv[])
|
||||
BMK_setBlockSize(blockSize);
|
||||
BMK_setNbThreads(nbThreads);
|
||||
BMK_setNbSeconds(bench_nbSeconds);
|
||||
BMK_setLdmFlag(ldmFlag);
|
||||
BMK_setLdmMinMatch(g_ldmMinMatch);
|
||||
BMK_setLdmHashLog(g_ldmHashLog);
|
||||
if (g_ldmBucketSizeLog != LDM_PARAM_DEFAULT) {
|
||||
BMK_setLdmBucketSizeLog(g_ldmBucketSizeLog);
|
||||
}
|
||||
if (g_ldmHashEveryLog != LDM_PARAM_DEFAULT) {
|
||||
BMK_setLdmHashEveryLog(g_ldmHashEveryLog);
|
||||
}
|
||||
BMK_benchFiles(filenameTable, filenameIdx, dictFileName, cLevel, cLevelLast, &compressionParams, setRealTimePrio);
|
||||
#endif
|
||||
(void)bench_nbSeconds; (void)blockSize; (void)setRealTimePrio;
|
||||
@@ -759,13 +737,13 @@ int main(int argCount, const char* argv[])
|
||||
int const optimize = !coverParams.k || !coverParams.d;
|
||||
coverParams.nbThreads = nbThreads;
|
||||
coverParams.zParams = zParams;
|
||||
operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, blockSize, NULL, &coverParams, optimize);
|
||||
operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, NULL, &coverParams, optimize);
|
||||
} else {
|
||||
ZDICT_legacy_params_t dictParams;
|
||||
memset(&dictParams, 0, sizeof(dictParams));
|
||||
dictParams.selectivityLevel = dictSelect;
|
||||
dictParams.zParams = zParams;
|
||||
operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, blockSize, &dictParams, NULL, 0);
|
||||
operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, &dictParams, NULL, 0);
|
||||
}
|
||||
#endif
|
||||
goto _end;
|
||||
@@ -809,16 +787,6 @@ int main(int argCount, const char* argv[])
|
||||
#ifndef ZSTD_NOCOMPRESS
|
||||
FIO_setNbThreads(nbThreads);
|
||||
FIO_setBlockSize((U32)blockSize);
|
||||
FIO_setLdmFlag(ldmFlag);
|
||||
FIO_setLdmHashLog(g_ldmHashLog);
|
||||
FIO_setLdmMinMatch(g_ldmMinMatch);
|
||||
if (g_ldmBucketSizeLog != LDM_PARAM_DEFAULT) {
|
||||
FIO_setLdmBucketSizeLog(g_ldmBucketSizeLog);
|
||||
}
|
||||
if (g_ldmHashEveryLog != LDM_PARAM_DEFAULT) {
|
||||
FIO_setLdmHashEveryLog(g_ldmHashEveryLog);
|
||||
}
|
||||
|
||||
if (g_overlapLog!=OVERLAP_LOG_DEFAULT) FIO_setOverlapLog(g_overlapLog);
|
||||
if ((filenameIdx==1) && outFileName)
|
||||
operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel, &compressionParams);
|
||||
|
||||
@@ -21,7 +21,6 @@ symbols
|
||||
legacy
|
||||
decodecorpus
|
||||
pool
|
||||
poolTests
|
||||
invalidDictionaries
|
||||
|
||||
# Tmp test directory
|
||||
@@ -49,7 +48,6 @@ grillResults.txt
|
||||
_*
|
||||
tmp*
|
||||
*.zst
|
||||
*.gz
|
||||
result
|
||||
out
|
||||
|
||||
|
||||
+22
-18
@@ -1,11 +1,13 @@
|
||||
# ################################################################
|
||||
# Copyright (c) 2015-present, Yann Collet, Facebook, Inc.
|
||||
# ##########################################################################
|
||||
# Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# ################################################################
|
||||
# This Makefile is validated for Linux, macOS, *BSD, Hurd, Solaris, MSYS2 targets
|
||||
#
|
||||
# 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.
|
||||
# ##########################################################################
|
||||
# datagen : Synthetic and parametrable data generator, for tests
|
||||
# fullbench : Precisely measure speed for each zstd inner functions
|
||||
# fullbench32: Same as fullbench, but forced to compile in 32-bits mode
|
||||
@@ -44,6 +46,10 @@ ZSTD_FILES := $(ZSTDDECOMP_FILES) $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES)
|
||||
ZBUFF_FILES := $(ZSTDDIR)/deprecated/*.c
|
||||
ZDICT_FILES := $(ZSTDDIR)/dictBuilder/*.c
|
||||
|
||||
ZSTD_OBJ := $(patsubst %.c,%.o, $(wildcard $(ZSTD_FILES)) )
|
||||
ZBUFF_OBJ := $(patsubst %.c,%.o, $(wildcard $(ZBUFF_FILES)) )
|
||||
ZDICT_OBJ := $(patsubst %.c,%.o, $(wildcard $(ZDICT_FILES)) )
|
||||
|
||||
|
||||
# Define *.exe as extension for Windows systems
|
||||
ifneq (,$(filter Windows%,$(OS)))
|
||||
@@ -71,7 +77,7 @@ all: fullbench fuzzer zstreamtest paramgrill datagen decodecorpus
|
||||
|
||||
all32: fullbench32 fuzzer32 zstreamtest32
|
||||
|
||||
allnothread: fullbench fuzzer paramgrill datagen decodecorpus
|
||||
allnothread: fullbench fuzzer paramgrill datagen decodecorpus
|
||||
|
||||
dll: fuzzer-dll zstreamtest-dll
|
||||
|
||||
@@ -85,7 +91,7 @@ zstd-nolegacy:
|
||||
$(MAKE) -C $(PRGDIR) $@
|
||||
|
||||
gzstd:
|
||||
$(MAKE) -C $(PRGDIR) zstd HAVE_ZLIB=1
|
||||
$(MAKE) -C $(PRGDIR) $@
|
||||
|
||||
fullbench32: CPPFLAGS += -m32
|
||||
fullbench fullbench32 : CPPFLAGS += $(MULTITHREAD_CPP)
|
||||
@@ -161,7 +167,7 @@ datagen : $(PRGDIR)/datagen.c datagencli.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
roundTripCrash : $(ZSTD_FILES) roundTripCrash.c
|
||||
$(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
longmatch : $(ZSTD_FILES) longmatch.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
@@ -186,8 +192,8 @@ else
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT) -Wl,-rpath=$(ZSTDDIR) $(ZSTDDIR)/libzstd.so
|
||||
endif
|
||||
|
||||
poolTests : poolTests.c $(ZSTDDIR)/common/pool.c $(ZSTDDIR)/common/threading.c $(ZSTDDIR)/common/zstd_common.c $(ZSTDDIR)/common/error_private.c
|
||||
$(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
|
||||
poolTests : poolTests.c $(ZSTDDIR)/common/pool.c $(ZSTDDIR)/common/threading.c
|
||||
$(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
|
||||
|
||||
namespaceTest:
|
||||
if $(CC) namespaceTest.c ../lib/common/xxhash.c -o $@ ; then echo compilation should fail; exit 1 ; fi
|
||||
@@ -278,13 +284,13 @@ test-zstd-nolegacy: ZSTD = $(PRGDIR)/zstd-nolegacy
|
||||
test-zstd-nolegacy: zstd-nolegacy zstd-playTests
|
||||
|
||||
test-gzstd: gzstd
|
||||
$(PRGDIR)/zstd -f README.md test-zstd-speed.py
|
||||
gzip -f README.md test-zstd-speed.py
|
||||
$(PRGDIR)/zstd README.md test-zstd-speed.py
|
||||
gzip README.md test-zstd-speed.py
|
||||
cat README.md.zst test-zstd-speed.py.gz >zstd_gz.zst
|
||||
cat README.md.gz test-zstd-speed.py.zst >gz_zstd.gz
|
||||
$(PRGDIR)/zstd -df README.md.gz -o README2.md
|
||||
$(PRGDIR)/zstd -df README.md.gz test-zstd-speed.py.gz
|
||||
$(PRGDIR)/zstd -df zstd_gz.zst gz_zstd.gz
|
||||
$(PRGDIR)/zstd -d README.md.gz -o README2.md
|
||||
$(PRGDIR)/zstd -d README.md.gz test-zstd-speed.py.gz
|
||||
$(PRGDIR)/zstd -d zstd_gz.zst gz_zstd.gz
|
||||
$(DIFF) -q zstd_gz gz_zstd
|
||||
echo Hello World ZSTD | $(PRGDIR)/zstd -c - >hello.zst
|
||||
echo Hello World GZIP | gzip -c - >hello.gz
|
||||
@@ -292,7 +298,6 @@ test-gzstd: gzstd
|
||||
cat hello.zst hello.gz hello.txt >hello_zst_gz_txt.gz
|
||||
$(PRGDIR)/zstd -dcf hello.*
|
||||
$(PRGDIR)/zstd -dcf - <hello_zst_gz_txt.gz
|
||||
$(RM) *.gz *.zst README2.md gz_zstd zstd_gz hello.txt
|
||||
|
||||
test-fullbench: fullbench datagen
|
||||
$(QEMU_SYS) ./fullbench -i1
|
||||
@@ -318,7 +323,6 @@ 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)
|
||||
|
||||
test-zstream32: zstreamtest32
|
||||
$(QEMU_SYS) ./zstreamtest32 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
|
||||
|
||||
+1
-2
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2015-present, Yann Collet, Facebook, Inc.
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
+71
-247
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2017-present, Yann Collet, Facebook, Inc.
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
@@ -174,8 +173,7 @@ 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 MAX_BLOCK_SIZE (128ULL * 1024)
|
||||
|
||||
#define MIN_SEQ_LEN (3)
|
||||
#define MAX_NB_SEQ ((MAX_BLOCK_SIZE + MIN_SEQ_LEN - 1) / MIN_SEQ_LEN)
|
||||
@@ -239,18 +237,6 @@ typedef struct {
|
||||
size_t dictContentSize;
|
||||
BYTE* dictContent;
|
||||
} dictInfo;
|
||||
|
||||
typedef enum {
|
||||
gt_frame = 0, /* generate frames */
|
||||
gt_block, /* generate compressed blocks without block/frame headers */
|
||||
} genType_e;
|
||||
|
||||
/*-*******************************************************
|
||||
* Global variables (set from command line)
|
||||
*********************************************************/
|
||||
U32 g_maxDecompressedSizeLog = MAX_DECOMPRESSED_SIZE_LOG; /* <= 20 */
|
||||
U32 g_maxBlockSize = MAX_BLOCK_SIZE; /* <= 128 KB */
|
||||
|
||||
/*-*******************************************************
|
||||
* Generator Functions
|
||||
*********************************************************/
|
||||
@@ -287,12 +273,12 @@ static void writeFrameHeader(U32* seed, frame_t* frame, dictInfo info)
|
||||
{
|
||||
/* Generate random content size */
|
||||
size_t highBit;
|
||||
if (RAND(seed) & 7 && g_maxDecompressedSizeLog > 7) {
|
||||
if (RAND(seed) & 7) {
|
||||
/* do content of at least 128 bytes */
|
||||
highBit = 1ULL << RAND_range(seed, 7, g_maxDecompressedSizeLog);
|
||||
highBit = 1ULL << RAND_range(seed, 7, MAX_DECOMPRESSED_SIZE_LOG);
|
||||
} else if (RAND(seed) & 3) {
|
||||
/* do small content */
|
||||
highBit = 1ULL << RAND_range(seed, 0, MIN(7, 1U << g_maxDecompressedSizeLog));
|
||||
highBit = 1ULL << RAND_range(seed, 0, 7);
|
||||
} else {
|
||||
/* 0 size frame */
|
||||
highBit = 0;
|
||||
@@ -372,7 +358,7 @@ static size_t writeLiteralsBlockSimple(U32* seed, frame_t* frame, size_t content
|
||||
int const type = RAND(seed) % 2;
|
||||
int const sizeFormatDesc = RAND(seed) % 8;
|
||||
size_t litSize;
|
||||
size_t maxLitSize = MIN(contentSize, g_maxBlockSize);
|
||||
size_t maxLitSize = MIN(contentSize, MAX_BLOCK_SIZE);
|
||||
|
||||
if (sizeFormatDesc == 0) {
|
||||
/* Size_FormatDesc = ?0 */
|
||||
@@ -466,7 +452,7 @@ static size_t writeHufHeader(U32* seed, HUF_CElt* hufTable, void* dst, size_t ds
|
||||
return op - ostart;
|
||||
}
|
||||
|
||||
/* Write a Huffman coded literals block and return the literals size */
|
||||
/* Write a Huffman coded literals block and return the litearls size */
|
||||
static size_t writeLiteralsBlockCompressed(U32* seed, frame_t* frame, size_t contentSize)
|
||||
{
|
||||
BYTE* origop = (BYTE*)frame->data;
|
||||
@@ -477,7 +463,7 @@ static size_t writeLiteralsBlockCompressed(U32* seed, frame_t* frame, size_t con
|
||||
size_t litSize;
|
||||
size_t hufHeaderSize = 0;
|
||||
size_t compressedSize = 0;
|
||||
size_t maxLitSize = MIN(contentSize-3, g_maxBlockSize);
|
||||
size_t maxLitSize = MIN(contentSize-3, MAX_BLOCK_SIZE);
|
||||
|
||||
symbolEncodingType_e hType;
|
||||
|
||||
@@ -1094,7 +1080,7 @@ static void writeBlock(U32* seed, frame_t* frame, size_t contentSize,
|
||||
static void writeBlocks(U32* seed, frame_t* frame, dictInfo info)
|
||||
{
|
||||
size_t contentLeft = frame->header.contentSize;
|
||||
size_t const maxBlockSize = MIN(g_maxBlockSize, frame->header.windowSize);
|
||||
size_t const maxBlockSize = MIN(MAX_BLOCK_SIZE, frame->header.windowSize);
|
||||
while (1) {
|
||||
/* 1 in 4 chance of ending frame */
|
||||
int const lastBlock = contentLeft > maxBlockSize ? 0 : !(RAND(seed) & 3);
|
||||
@@ -1178,61 +1164,6 @@ static void initFrame(frame_t* fr)
|
||||
fr->stats.rep[2] = 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated a single zstd compressed block with no block/frame header.
|
||||
* Returns the final seed.
|
||||
*/
|
||||
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);
|
||||
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 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);
|
||||
if (RAND(&seed) & 15) {
|
||||
/* some full size blocks */
|
||||
blockContentSize = maxBlockSize;
|
||||
} else if (RAND(&seed) & 7 && g_maxBlockSize >= (1U << 7)) {
|
||||
/* some small blocks <= 128 bytes*/
|
||||
blockContentSize = RAND(&seed) % (1U << 7);
|
||||
} else {
|
||||
/* some variable size blocks */
|
||||
blockContentSize = RAND(&seed) % maxBlockSize;
|
||||
}
|
||||
}
|
||||
|
||||
/* try generating a compressed block */
|
||||
frame->oldStats = frame->stats;
|
||||
frame->data = op;
|
||||
cSize = writeCompressedBlock(&seed, frame, blockContentSize, info);
|
||||
if (cSize > blockContentSize) {
|
||||
/* data doesn't compress -- try again */
|
||||
frame->stats = frame->oldStats; /* don't update the stats */
|
||||
DISPLAYLEVEL(3, " can't compress block\n");
|
||||
} else {
|
||||
blockWritten = 1;
|
||||
DISPLAYLEVEL(3, " block size: %u\n", (U32)cSize);
|
||||
frame->src = (BYTE*)frame->src + blockContentSize;
|
||||
}
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
|
||||
/* Return the final seed */
|
||||
static U32 generateFrame(U32 seed, frame_t* fr, dictInfo info)
|
||||
{
|
||||
@@ -1391,7 +1322,7 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t testDecodeWithDict(U32 seed, genType_e genType)
|
||||
static size_t testDecodeWithDict(U32 seed)
|
||||
{
|
||||
/* create variables */
|
||||
size_t const dictSize = RAND(&seed) % (10 << 20) + ZDICT_DICTSIZE_MIN + ZDICT_CONTENTSIZE_MIN;
|
||||
@@ -1414,47 +1345,34 @@ static size_t testDecodeWithDict(U32 seed, genType_e genType)
|
||||
|
||||
{
|
||||
frame_t fr;
|
||||
dictInfo info;
|
||||
ZSTD_DCtx* const dctx = ZSTD_createDCtx();
|
||||
size_t ret;
|
||||
|
||||
/* get dict info */
|
||||
/* generate frame */
|
||||
{
|
||||
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);
|
||||
dictInfo const info = initDictInfo(1, dictContentSize, dictContent, dictID);
|
||||
seed = generateFrame(seed, &fr, info);
|
||||
}
|
||||
|
||||
/* manually decompress and check difference */
|
||||
if (genType == gt_frame) {
|
||||
/* Test frame */
|
||||
seed = 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);
|
||||
ret = ZSTD_decompressBegin_usingDict(dctx, fullDict, dictSize);
|
||||
if (ZSTD_isError(ret)) {
|
||||
errorDetected = ret;
|
||||
ZSTD_freeDCtx(dctx);
|
||||
{
|
||||
ZSTD_DCtx* const dctx = ZSTD_createDCtx();
|
||||
{
|
||||
size_t const returnValue = ZSTD_decompress_usingDict(dctx, DECOMPRESSED_BUFFER, MAX_DECOMPRESSED_SIZE,
|
||||
fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart,
|
||||
fullDict, dictSize);
|
||||
if (ZSTD_isError(returnValue)) {
|
||||
errorDetected = returnValue;
|
||||
goto dictTestCleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(DECOMPRESSED_BUFFER, fr.srcStart, (BYTE*)fr.src - (BYTE*)fr.srcStart) != 0) {
|
||||
errorDetected = ERROR(corruption_detected);
|
||||
goto dictTestCleanup;
|
||||
}
|
||||
ret = ZSTD_decompressBlock(dctx, DECOMPRESSED_BUFFER, MAX_DECOMPRESSED_SIZE,
|
||||
fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart);
|
||||
}
|
||||
ZSTD_freeDCtx(dctx);
|
||||
|
||||
if (ZSTD_isError(ret)) {
|
||||
errorDetected = ret;
|
||||
goto dictTestCleanup;
|
||||
}
|
||||
|
||||
if (memcmp(DECOMPRESSED_BUFFER, fr.srcStart, (BYTE*)fr.src - (BYTE*)fr.srcStart) != 0) {
|
||||
errorDetected = ERROR(corruption_detected);
|
||||
goto dictTestCleanup;
|
||||
ZSTD_freeDCtx(dctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1463,91 +1381,7 @@ dictTestCleanup:
|
||||
return errorDetected;
|
||||
}
|
||||
|
||||
static size_t testDecodeRawBlock(frame_t* fr)
|
||||
{
|
||||
ZSTD_DCtx* dctx = ZSTD_createDCtx();
|
||||
size_t ret = ZSTD_decompressBegin(dctx);
|
||||
if (ZSTD_isError(ret)) return ret;
|
||||
|
||||
ret = ZSTD_decompressBlock(
|
||||
dctx,
|
||||
DECOMPRESSED_BUFFER, MAX_DECOMPRESSED_SIZE,
|
||||
fr->dataStart, (BYTE*)fr->data - (BYTE*)fr->dataStart);
|
||||
ZSTD_freeDCtx(dctx);
|
||||
if (ZSTD_isError(ret)) return ret;
|
||||
|
||||
if (memcmp(DECOMPRESSED_BUFFER, fr->srcStart,
|
||||
(BYTE*)fr->src - (BYTE*)fr->srcStart) != 0) {
|
||||
return ERROR(corruption_detected);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int runBlockTest(U32* seed)
|
||||
{
|
||||
frame_t fr;
|
||||
U32 const seedCopy = *seed;
|
||||
{
|
||||
dictInfo const info = initDictInfo(0, 0, NULL, 0);
|
||||
*seed = generateCompressedBlock(*seed, &fr, info);
|
||||
}
|
||||
|
||||
{ size_t const r = testDecodeRawBlock(&fr);
|
||||
if (ZSTD_isError(r)) {
|
||||
DISPLAY("Error in block mode on test seed %u: %s\n", seedCopy,
|
||||
ZSTD_getErrorName(r));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
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));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int runFrameTest(U32* seed)
|
||||
{
|
||||
frame_t fr;
|
||||
U32 const seedCopy = *seed;
|
||||
{
|
||||
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));
|
||||
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));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
{
|
||||
/* don't create a dictionary that is too big */
|
||||
size_t const r = testDecodeWithDict(*seed, gt_frame);
|
||||
if (ZSTD_isError(r)) {
|
||||
DISPLAY("Error in dictionary mode on test seed %u: %s\n", seedCopy, ZSTD_getErrorName(r));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int runTestMode(U32 seed, unsigned numFiles, unsigned const testDurationS,
|
||||
genType_e genType)
|
||||
static int runTestMode(U32 seed, unsigned numFiles, unsigned const testDurationS)
|
||||
{
|
||||
unsigned fnum;
|
||||
|
||||
@@ -1559,21 +1393,39 @@ static int runTestMode(U32 seed, unsigned numFiles, unsigned const testDurationS
|
||||
DISPLAY("seed: %u\n", seed);
|
||||
|
||||
for (fnum = 0; fnum < numFiles || clockSpan(startClock) < maxClockSpan; fnum++) {
|
||||
frame_t fr;
|
||||
U32 const seedCopy = seed;
|
||||
if (fnum < numFiles)
|
||||
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;
|
||||
}
|
||||
{
|
||||
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));
|
||||
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));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
{
|
||||
/* don't create a dictionary that is too big */
|
||||
size_t const r = testDecodeWithDict(seed);
|
||||
if (ZSTD_isError(r)) {
|
||||
DISPLAY("Error in dictionary mode on test seed %u: %s\n", seedCopy, ZSTD_getErrorName(r));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1588,7 +1440,7 @@ static int runTestMode(U32 seed, unsigned numFiles, unsigned const testDurationS
|
||||
*********************************************************/
|
||||
|
||||
static int generateFile(U32 seed, const char* const path,
|
||||
const char* const origPath, genType_e genType)
|
||||
const char* const origPath)
|
||||
{
|
||||
frame_t fr;
|
||||
|
||||
@@ -1596,12 +1448,9 @@ static int generateFile(U32 seed, const char* const path,
|
||||
|
||||
{
|
||||
dictInfo const info = initDictInfo(0, 0, NULL, 0);
|
||||
if (genType == gt_frame) {
|
||||
generateFrame(seed, &fr, info);
|
||||
} else {
|
||||
generateCompressedBlock(seed, &fr, info);
|
||||
}
|
||||
generateFrame(seed, &fr, info);
|
||||
}
|
||||
|
||||
outputBuffer(fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart, path);
|
||||
if (origPath) {
|
||||
outputBuffer(fr.srcStart, (BYTE*)fr.src - (BYTE*)fr.srcStart, origPath);
|
||||
@@ -1610,7 +1459,7 @@ static int generateFile(U32 seed, const char* const path,
|
||||
}
|
||||
|
||||
static int generateCorpus(U32 seed, unsigned numFiles, const char* const path,
|
||||
const char* const origPath, genType_e genType)
|
||||
const char* const origPath)
|
||||
{
|
||||
char outPath[MAX_PATH];
|
||||
unsigned fnum;
|
||||
@@ -1624,11 +1473,7 @@ static int generateCorpus(U32 seed, unsigned numFiles, const char* const path,
|
||||
|
||||
{
|
||||
dictInfo const info = initDictInfo(0, 0, NULL, 0);
|
||||
if (genType == gt_frame) {
|
||||
seed = generateFrame(seed, &fr, info);
|
||||
} else {
|
||||
seed = generateCompressedBlock(seed, &fr, info);
|
||||
}
|
||||
seed = generateFrame(seed, &fr, info);
|
||||
}
|
||||
|
||||
if (snprintf(outPath, MAX_PATH, "%s/z%06u.zst", path, fnum) + 1 > MAX_PATH) {
|
||||
@@ -1652,8 +1497,7 @@ static int generateCorpus(U32 seed, unsigned numFiles, const char* const path,
|
||||
}
|
||||
|
||||
static int generateCorpusWithDict(U32 seed, unsigned numFiles, const char* const path,
|
||||
const char* const origPath, const size_t dictSize,
|
||||
genType_e genType)
|
||||
const char* const origPath, const size_t dictSize)
|
||||
{
|
||||
char outPath[MAX_PATH];
|
||||
BYTE* fullDict;
|
||||
@@ -1705,11 +1549,7 @@ static int generateCorpusWithDict(U32 seed, unsigned numFiles, const char* const
|
||||
size_t const dictContentSize = dictSize-headerSize;
|
||||
BYTE* const dictContent = fullDict+headerSize;
|
||||
dictInfo const info = initDictInfo(1, dictContentSize, dictContent, dictID);
|
||||
if (genType == gt_frame) {
|
||||
seed = generateFrame(seed, &fr, info);
|
||||
} else {
|
||||
seed = generateCompressedBlock(seed, &fr, info);
|
||||
}
|
||||
seed = generateFrame(seed, &fr, info);
|
||||
}
|
||||
|
||||
if (numFiles != 0) {
|
||||
@@ -1786,13 +1626,9 @@ static void advancedUsage(const char* programName)
|
||||
{
|
||||
usage(programName);
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Advanced arguments :\n");
|
||||
DISPLAY( " --content-size : always include the content size in the frame header\n");
|
||||
DISPLAY( " --use-dict=# : include a dictionary used to decompress the corpus\n");
|
||||
DISPLAY( " --gen-blocks : generate raw compressed blocks without block/frame headers\n");
|
||||
DISPLAY( " --max-block-size-log=# : max block size log, must be in range [2, 17]\n");
|
||||
DISPLAY( " --max-content-size-log=# : max content size log, must be <= 20\n");
|
||||
DISPLAY( " (this is ignored with gen-blocks)\n");
|
||||
DISPLAY( "Advanced arguments :\n");
|
||||
DISPLAY( " --content-size : always include the content size in the frame header\n");
|
||||
DISPLAY( " --use-dict=# : include a dictionary used to decompress the corpus\n");
|
||||
}
|
||||
|
||||
/*! readU32FromChar() :
|
||||
@@ -1839,7 +1675,6 @@ int main(int argc, char** argv)
|
||||
const char* origPath = NULL;
|
||||
int useDict = 0;
|
||||
unsigned dictSize = (10 << 10); /* 10 kB default */
|
||||
genType_e genType = gt_frame;
|
||||
|
||||
int argNb;
|
||||
|
||||
@@ -1903,17 +1738,6 @@ int main(int argc, char** argv)
|
||||
} else if (longCommandWArg(&argument, "use-dict=")) {
|
||||
dictSize = readU32FromChar(&argument);
|
||||
useDict = 1;
|
||||
} else if (strcmp(argument, "gen-blocks") == 0) {
|
||||
genType = gt_block;
|
||||
} else if (longCommandWArg(&argument, "max-block-size-log=")) {
|
||||
U32 value = readU32FromChar(&argument);
|
||||
if (value >= 2 && value <= MAX_BLOCK_SIZE) {
|
||||
g_maxBlockSize = 1U << value;
|
||||
}
|
||||
} else if (longCommandWArg(&argument, "max-content-size-log=")) {
|
||||
U32 value = readU32FromChar(&argument);
|
||||
g_maxDecompressedSizeLog =
|
||||
MIN(MAX_DECOMPRESSED_SIZE_LOG, value);
|
||||
} else {
|
||||
advancedUsage(argv[0]);
|
||||
return 1;
|
||||
@@ -1930,7 +1754,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
if (testMode) {
|
||||
return runTestMode(seed, numFiles, testDuration, genType);
|
||||
return runTestMode(seed, numFiles, testDuration);
|
||||
} else {
|
||||
if (testDuration) {
|
||||
DISPLAY("Error: -T requires test mode (-t)\n\n");
|
||||
@@ -1946,12 +1770,12 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
if (numFiles == 0 && useDict == 0) {
|
||||
return generateFile(seed, path, origPath, genType);
|
||||
return generateFile(seed, path, origPath);
|
||||
} else if (useDict == 0){
|
||||
return generateCorpus(seed, numFiles, path, origPath, genType);
|
||||
return generateCorpus(seed, numFiles, path, origPath);
|
||||
} else {
|
||||
/* should generate files with a dictionary */
|
||||
return generateCorpusWithDict(seed, numFiles, path, origPath, dictSize, genType);
|
||||
return generateCorpusWithDict(seed, numFiles, path, origPath, dictSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-6
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2015-present, Yann Collet, Facebook, Inc.
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
|
||||
@@ -422,6 +421,8 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb)
|
||||
{ U32 loopNb;
|
||||
# define TIME_SEC_MICROSEC (1*1000000ULL) /* 1 second */
|
||||
U64 const clockLoop = TIMELOOP_S * TIME_SEC_MICROSEC;
|
||||
UTIL_freq_t ticksPerSecond;
|
||||
UTIL_initTimer(&ticksPerSecond);
|
||||
DISPLAY("%2i- %-30.30s : \r", benchNb, benchName);
|
||||
for (loopNb = 1; loopNb <= g_nbIterations; loopNb++) {
|
||||
UTIL_time_t clockStart;
|
||||
@@ -429,13 +430,13 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb)
|
||||
U32 nbRounds;
|
||||
|
||||
UTIL_sleepMilli(1); /* give processor time to other processes */
|
||||
UTIL_waitForNextTick();
|
||||
clockStart = UTIL_getTime();
|
||||
for (nbRounds=0; UTIL_clockSpanMicro(clockStart) < clockLoop; nbRounds++) {
|
||||
UTIL_waitForNextTick(ticksPerSecond);
|
||||
UTIL_getTime(&clockStart);
|
||||
for (nbRounds=0; UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop; nbRounds++) {
|
||||
benchResult = benchFunction(dstBuff, dstBuffSize, buff2, src, srcSize);
|
||||
if (ZSTD_isError(benchResult)) { DISPLAY("ERROR ! %s() => %s !! \n", benchName, ZSTD_getErrorName(benchResult)); exit(1); }
|
||||
}
|
||||
{ U64 const clockSpanMicro = UTIL_clockSpanMicro(clockStart);
|
||||
{ U64 const clockSpanMicro = UTIL_clockSpanMicro(clockStart, ticksPerSecond);
|
||||
double const averageTime = (double)clockSpanMicro / TIME_SEC_MICROSEC / nbRounds;
|
||||
if (averageTime < bestTime) bestTime = averageTime;
|
||||
DISPLAY("%2i- %-30.30s : %7.1f MB/s (%9u)\r", loopNb, benchName, (double)srcSize / (1 MB) / bestTime, (U32)benchResult);
|
||||
|
||||
+57
-48
@@ -1,89 +1,98 @@
|
||||
# ################################################################
|
||||
# ##########################################################################
|
||||
# Copyright (c) 2016-present, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# ################################################################
|
||||
# This Makefile is validated for Linux, and macOS targets
|
||||
#
|
||||
# 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.
|
||||
# ##########################################################################
|
||||
|
||||
# Optionally user defined flags
|
||||
CFLAGS ?= -O3
|
||||
CXXFLAGS ?= -O3
|
||||
CPPFLAGS ?=
|
||||
LDFLAGS ?=
|
||||
ARFLAGS ?=
|
||||
LIB_FUZZING_ENGINE ?= libregression.a
|
||||
|
||||
ZSTDDIR = ../../lib
|
||||
PRGDIR = ../../programs
|
||||
|
||||
FUZZ_CPPFLAGS := -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/compress \
|
||||
-I$(ZSTDDIR)/dictBuilder -I$(ZSTDDIR)/deprecated -I$(PRGDIR) \
|
||||
$(CPPFLAGS)
|
||||
FUZZ_EXTRA_FLAGS := -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
|
||||
-DZSTD_DEBUG=1 -DMEM_FORCE_MEMORY_ACCESS=0 \
|
||||
-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION $(CPPFLAGS)
|
||||
FUZZ_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 \
|
||||
-g -fno-omit-frame-pointer
|
||||
FUZZ_CFLAGS := $(FUZZ_EXTRA_FLAGS) $(CFLAGS)
|
||||
FUZZ_CXXFLAGS := $(FUZZ_EXTRA_FLAGS) -std=c++11 $(CXXFLAGS)
|
||||
-g -fno-omit-frame-pointer $(CFLAGS)
|
||||
FUZZ_CXXFLAGS := -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 \
|
||||
-g -fno-omit-frame-pointer -std=c++11 $(CXXFLAGS)
|
||||
FUZZ_LDFLAGS := $(LDFLAGS)
|
||||
FUZZ_ARFLAGS := $(ARFLAGS)
|
||||
FUZZ_TARGET_FLAGS = $(FUZZ_CPPFLAGS) $(FUZZ_CXXFLAGS) $(FUZZ_LDFLAGS)
|
||||
|
||||
FUZZ_HEADERS := fuzz_helpers.h fuzz.h zstd_helpers.h
|
||||
FUZZ_SRC := zstd_helpers.c
|
||||
FUZZ_HEADERS := fuzz_helpers.h fuzz.h
|
||||
|
||||
ZSTDCOMMON_SRC := $(ZSTDDIR)/common/*.c
|
||||
ZSTDCOMP_SRC := $(ZSTDDIR)/compress/*.c
|
||||
ZSTDDECOMP_SRC := $(ZSTDDIR)/decompress/*.c
|
||||
FUZZ_SRC := \
|
||||
$(FUZZ_SRC) \
|
||||
$(ZSTDDECOMP_SRC) \
|
||||
$(ZSTDCOMMON_SRC) \
|
||||
$(ZSTDCOMP_SRC)
|
||||
ZSTDCOMMON_FILES := $(ZSTDDIR)/common/*.c
|
||||
ZSTDCOMP_FILES := $(ZSTDDIR)/compress/*.c
|
||||
ZSTDDECOMP_FILES := $(ZSTDDIR)/decompress/*.c
|
||||
ZSTD_FILES := $(ZSTDDECOMP_FILES) $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES)
|
||||
|
||||
FUZZ_OBJ := $(patsubst %.c,%.o, $(wildcard $(FUZZ_SRC)))
|
||||
ZSTD_OBJ := $(patsubst %.c,%.o, $(wildcard $(ZSTD_FILES)))
|
||||
|
||||
LIBFUZZER ?= -lFuzzer
|
||||
|
||||
.PHONY: default all clean
|
||||
|
||||
default: all
|
||||
|
||||
all: \
|
||||
simple_round_trip \
|
||||
stream_round_trip \
|
||||
block_round_trip \
|
||||
simple_decompress \
|
||||
stream_decompress \
|
||||
block_decompress
|
||||
all: round_trip simple_decompress
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $^ -c -o $@
|
||||
|
||||
simple_round_trip: $(FUZZ_HEADERS) $(FUZZ_OBJ) simple_round_trip.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) simple_round_trip.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
simple_round_trip: $(FUZZ_HEADERS) $(ZSTD_OBJ) simple_round_trip.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) simple_round_trip.o $(LIBFUZZER) -o $@
|
||||
|
||||
stream_round_trip: $(FUZZ_HEADERS) $(FUZZ_OBJ) stream_round_trip.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) stream_round_trip.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
stream_round_trip: $(FUZZ_HEADERS) $(ZSTD_OBJ) stream_round_trip.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) stream_round_trip.o $(LIBFUZZER) -o $@
|
||||
|
||||
block_round_trip: $(FUZZ_HEADERS) $(FUZZ_OBJ) block_round_trip.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) block_round_trip.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
simple_decompress: $(FUZZ_HEADERS) $(ZSTD_OBJ) simple_decompress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) simple_decompress.o $(LIBFUZZER) -o $@
|
||||
|
||||
simple_decompress: $(FUZZ_HEADERS) $(FUZZ_OBJ) simple_decompress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) simple_decompress.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
|
||||
stream_decompress: $(FUZZ_HEADERS) $(FUZZ_OBJ) stream_decompress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) stream_decompress.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
|
||||
block_decompress: $(FUZZ_HEADERS) $(FUZZ_OBJ) block_decompress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) block_decompress.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
stream_decompress: $(FUZZ_HEADERS) $(ZSTD_OBJ) stream_decompress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) stream_decompress.o $(LIBFUZZER) -o $@
|
||||
|
||||
libregression.a: $(FUZZ_HEADERS) $(PRGDIR)/util.h regression_driver.o
|
||||
$(AR) $(FUZZ_ARFLAGS) $@ regression_driver.o
|
||||
|
||||
%-regression: libregression.a
|
||||
$(RM) $*
|
||||
$(MAKE) $* LDFLAGS="$(FUZZ_LDFLAGS) -L." LIBFUZZER=-lregression
|
||||
|
||||
%-regression-test: %-regression
|
||||
./$* corpora/$*
|
||||
|
||||
regression-test: \
|
||||
simple_round_trip-regression-test \
|
||||
stream_round_trip-regression-test \
|
||||
simple_decompress-regression-test \
|
||||
stream_decompress-regression-test
|
||||
|
||||
%-msan: clean
|
||||
$(MAKE) $* CFLAGS="-fsanitize=memory $(FUZZ_CFLAGS)" \
|
||||
CXXFLAGS="-fsanitize=memory $(FUZZ_CXXFLAGS)"
|
||||
|
||||
UASAN_FLAGS := -fsanitize=address,undefined -fno-sanitize-recover=undefined \
|
||||
-fno-sanitize=pointer-overflow
|
||||
%-uasan: clean
|
||||
$(MAKE) $* CFLAGS="$(FUZZ_CFLAGS) $(UASAN_FLAGS)" \
|
||||
CXXFLAGS="$(FUZZ_CXXFLAGS) $(UASAN_FLAGS)"
|
||||
|
||||
# Install libfuzzer (not usable for MSAN testing)
|
||||
# Provided for convienence. To use this library run make libFuzzer and
|
||||
# set LDFLAGS=-L.
|
||||
@@ -91,7 +100,7 @@ libregression.a: $(FUZZ_HEADERS) $(PRGDIR)/util.h regression_driver.o
|
||||
libFuzzer:
|
||||
@$(RM) -rf Fuzzer
|
||||
@git clone https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer
|
||||
@cd Fuzzer && ./build.sh
|
||||
@./Fuzzer/build.sh
|
||||
|
||||
clean:
|
||||
@$(MAKE) -C $(ZSTDDIR) clean
|
||||
|
||||
+16
-70
@@ -2,87 +2,33 @@
|
||||
|
||||
Each fuzzing target can be built with multiple engines.
|
||||
|
||||
## fuzz.py
|
||||
|
||||
`fuzz.py` is a helper script for building and running fuzzers.
|
||||
Run `./fuzz.py -h` for the commands and run `./fuzz.py COMMAND -h` for
|
||||
command specific help.
|
||||
|
||||
### Generating Data
|
||||
|
||||
`fuzz.py` provides a utility to generate seed data for each fuzzer.
|
||||
|
||||
```
|
||||
make -C ../tests decodecorpus
|
||||
./fuzz.py gen TARGET
|
||||
```
|
||||
|
||||
By default it outputs 100 samples, each at most 8KB into `corpora/TARGET-seed`,
|
||||
but that can be configured with the `--number`, `--max-size-log` and `--seed`
|
||||
flags.
|
||||
|
||||
### Build
|
||||
It respects the usual build environment variables `CC`, `CFLAGS`, etc.
|
||||
The environment variables can be overridden with the corresponding flags
|
||||
`--cc`, `--cflags`, etc.
|
||||
The specific fuzzing engine is selected with `LIB_FUZZING_ENGINE` or
|
||||
`--lib-fuzzing-engine`, the default is `libregression.a`.
|
||||
It has flags that can easily set up sanitizers `--enable-{a,ub,m}san`, and
|
||||
coverage instrumentation `--enable-coverage`.
|
||||
It sets sane defaults which can be overriden with flags `--debug`,
|
||||
`--enable-ubsan-pointer-overlow`, etc.
|
||||
Run `./fuzz.py build -h` for help.
|
||||
|
||||
### Running Fuzzers
|
||||
|
||||
`./fuzz.py` can run `libfuzzer`, `afl`, and `regression` tests.
|
||||
See the help of the relevant command for options.
|
||||
Flags not parsed by `fuzz.py` are passed to the fuzzing engine.
|
||||
The command used to run the fuzzer is printed for debugging.
|
||||
|
||||
## LibFuzzer
|
||||
|
||||
```
|
||||
# Build libfuzzer if necessary
|
||||
make libFuzzer
|
||||
# Build the fuzz targets
|
||||
./fuzz.py build all --enable-coverage --enable-asan --enable-ubsan --lib-fuzzing-engine Fuzzer/libFuzzer.a --cc clang --cxx clang++
|
||||
# OR equivalently
|
||||
CC=clang CXX=clang++ LIB_FUZZING_ENGINE=Fuzzer/libFuzzer.a ./fuzz.py build all --enable-coverage --enable-asan --enable-ubsan
|
||||
# Run the fuzzer
|
||||
./fuzz.py libfuzzer TARGET -max_len=8192 -jobs=4
|
||||
```
|
||||
|
||||
where `TARGET` could be `simple_decompress`, `stream_round_trip`, etc.
|
||||
|
||||
### MSAN
|
||||
|
||||
Fuzzing with `libFuzzer` and `MSAN` will require building a C++ standard library
|
||||
and libFuzzer with MSAN.
|
||||
`fuzz.py` respects the environment variables / flags `MSAN_EXTRA_CPPFLAGS`,
|
||||
`MSAN_EXTRA_CFLAGS`, `MSAN_EXTRA_CXXFLAGS`, `MSAN_EXTRA_LDFLAGS` to easily pass
|
||||
the extra parameters only for MSAN.
|
||||
You can install `libFuzzer` with `make libFuzzer`. Then you can make each target
|
||||
with `make target LDFLAGS=-L. CC=clang CXX=clang++`.
|
||||
|
||||
## AFL
|
||||
|
||||
The default `LIB_FUZZING_ENGINE` is `libregression.a`, which produces a binary
|
||||
that AFL can use.
|
||||
The regression driver also serves as a binary for `afl-fuzz`. You can make each
|
||||
target with one of these commands:
|
||||
|
||||
```
|
||||
# Build the fuzz targets
|
||||
CC=afl-clang CXX=afl-clang++ ./fuzz.py build all --enable-asan --enable-ubsan
|
||||
# Run the fuzzer without a memory limit because of ASAN
|
||||
./fuzz.py afl TARGET -m none
|
||||
make target-regression CC=afl-clang CXX=afl-clang++
|
||||
AFL_MSAN=1 make target-regression-msan CC=afl-clang CXX=afl-clang++
|
||||
AFL_ASAN=1 make target-regression-uasan CC=afl-clang CXX=afl-clang++
|
||||
```
|
||||
|
||||
Then run as `./target @@`.
|
||||
|
||||
## Regression Testing
|
||||
|
||||
The regression rest supports the `all` target to run all the fuzzers in one
|
||||
command.
|
||||
Each fuzz target has a corpus checked into the repo under `fuzz/corpora/`.
|
||||
You can run regression tests on the corpora to ensure that inputs which
|
||||
previously exposed bugs still pass. You can make these targets to run the
|
||||
regression tests with different sanitizers.
|
||||
|
||||
```
|
||||
CC=clang CXX=clang++ ./fuzz.py build all --enable-asan --enable-ubsan
|
||||
./fuzz.py regression all
|
||||
CC=clang CXX=clang++ ./fuzz.py build all --enable-msan
|
||||
./fuzz.py regression all
|
||||
make regression-test
|
||||
make regression-test-msan
|
||||
make regression-test-uasan
|
||||
```
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
*/
|
||||
|
||||
/**
|
||||
* This fuzz target attempts to decompress the fuzzed data with the simple
|
||||
* decompression function to ensure the decompressor never crashes.
|
||||
*/
|
||||
|
||||
#define ZSTD_STATIC_LINKING_ONLY
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd.h"
|
||||
|
||||
static ZSTD_DCtx *dctx = NULL;
|
||||
static void* rBuf = NULL;
|
||||
static size_t bufSize = 0;
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
size_t const neededBufSize = ZSTD_BLOCKSIZE_MAX;
|
||||
|
||||
FUZZ_seed(&src, &size);
|
||||
|
||||
/* Allocate all buffers and contexts if not already allocated */
|
||||
if (neededBufSize > bufSize) {
|
||||
free(rBuf);
|
||||
rBuf = malloc(neededBufSize);
|
||||
bufSize = neededBufSize;
|
||||
FUZZ_ASSERT(rBuf);
|
||||
}
|
||||
if (!dctx) {
|
||||
dctx = ZSTD_createDCtx();
|
||||
FUZZ_ASSERT(dctx);
|
||||
}
|
||||
ZSTD_decompressBegin(dctx);
|
||||
ZSTD_decompressBlock(dctx, rBuf, neededBufSize, src, size);
|
||||
|
||||
#ifndef STATEFUL_FUZZING
|
||||
ZSTD_freeDCtx(dctx); dctx = NULL;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
*/
|
||||
|
||||
/**
|
||||
* This fuzz target performs a zstd round-trip test (compress & decompress),
|
||||
* compares the result with the original, and calls abort() on corruption.
|
||||
*/
|
||||
|
||||
#define ZSTD_STATIC_LINKING_ONLY
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd.h"
|
||||
|
||||
static const int kMaxClevel = 19;
|
||||
|
||||
static ZSTD_CCtx *cctx = NULL;
|
||||
static ZSTD_DCtx *dctx = NULL;
|
||||
static void* cBuf = NULL;
|
||||
static void* rBuf = NULL;
|
||||
static size_t bufSize = 0;
|
||||
static uint32_t seed;
|
||||
|
||||
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);
|
||||
|
||||
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) {
|
||||
FUZZ_ASSERT(resultCapacity >= srcSize);
|
||||
memcpy(result, src, srcSize);
|
||||
return srcSize;
|
||||
}
|
||||
ZSTD_decompressBegin(dctx);
|
||||
return ZSTD_decompressBlock(dctx, result, resultCapacity, compressed, ret);
|
||||
}
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
size_t neededBufSize;
|
||||
|
||||
seed = FUZZ_seed(&src, &size);
|
||||
neededBufSize = size;
|
||||
if (size > ZSTD_BLOCKSIZE_MAX)
|
||||
return 0;
|
||||
|
||||
/* Allocate all buffers and contexts if not already allocated */
|
||||
if (neededBufSize > bufSize || !cBuf || !rBuf) {
|
||||
free(cBuf);
|
||||
free(rBuf);
|
||||
cBuf = malloc(neededBufSize);
|
||||
rBuf = malloc(neededBufSize);
|
||||
bufSize = neededBufSize;
|
||||
FUZZ_ASSERT(cBuf && rBuf);
|
||||
}
|
||||
if (!cctx) {
|
||||
cctx = ZSTD_createCCtx();
|
||||
FUZZ_ASSERT(cctx);
|
||||
}
|
||||
if (!dctx) {
|
||||
dctx = ZSTD_createDCtx();
|
||||
FUZZ_ASSERT(dctx);
|
||||
}
|
||||
|
||||
{
|
||||
size_t const result =
|
||||
roundTripTest(rBuf, neededBufSize, cBuf, neededBufSize, src, size);
|
||||
FUZZ_ASSERT_MSG(!ZSTD_isError(result), ZSTD_getErrorName(result));
|
||||
FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
|
||||
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
|
||||
}
|
||||
#ifndef STATEFUL_FUZZING
|
||||
ZSTD_freeCCtx(cctx); cctx = NULL;
|
||||
ZSTD_freeDCtx(dctx); dctx = NULL;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
+8
-18
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -12,17 +12,15 @@
|
||||
* Fuzz targets have some common parameters passed as macros during compilation.
|
||||
* Check the documentation for each individual fuzzer for more parameters.
|
||||
*
|
||||
* @param STATEFUL_FUZZING:
|
||||
* @param STATEFULL_FUZZING:
|
||||
* Define this to reuse state between fuzzer runs. This can be useful to
|
||||
* test code paths which are only executed when contexts are reused.
|
||||
* WARNING: Makes reproducing crashes much harder.
|
||||
* Default: Not defined.
|
||||
* @param FUZZ_RNG_SEED_SIZE:
|
||||
* The number of bytes of the source to look at when constructing a seed
|
||||
* for the deterministic RNG. These bytes are discarded before passing
|
||||
* the data to zstd functions. Every fuzzer initializes the RNG exactly
|
||||
* once before doing anything else, even if it is unused.
|
||||
* Default: 4.
|
||||
* for the deterministic RNG.
|
||||
* Default: 128.
|
||||
* @param ZSTD_DEBUG:
|
||||
* This is a parameter for the zstd library. Defining `ZSTD_DEBUG=1`
|
||||
* enables assert() statements in the zstd library. Higher levels enable
|
||||
@@ -43,20 +41,12 @@
|
||||
#define FUZZ_H
|
||||
|
||||
#ifndef FUZZ_RNG_SEED_SIZE
|
||||
# define FUZZ_RNG_SEED_SIZE 4
|
||||
# define FUZZ_RNG_SEED_SIZE 128
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,721 +0,0 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# ################################################################
|
||||
# Copyright (c) 2016-present, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# ##########################################################################
|
||||
|
||||
import argparse
|
||||
import contextlib
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
|
||||
def abs_join(a, *p):
|
||||
return os.path.abspath(os.path.join(a, *p))
|
||||
|
||||
|
||||
# Constants
|
||||
FUZZ_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
CORPORA_DIR = abs_join(FUZZ_DIR, 'corpora')
|
||||
TARGETS = [
|
||||
'simple_round_trip',
|
||||
'stream_round_trip',
|
||||
'block_round_trip',
|
||||
'simple_decompress',
|
||||
'stream_decompress',
|
||||
'block_decompress',
|
||||
]
|
||||
ALL_TARGETS = TARGETS + ['all']
|
||||
FUZZ_RNG_SEED_SIZE = 4
|
||||
|
||||
# Standard environment variables
|
||||
CC = os.environ.get('CC', 'cc')
|
||||
CXX = os.environ.get('CXX', 'c++')
|
||||
CPPFLAGS = os.environ.get('CPPFLAGS', '')
|
||||
CFLAGS = os.environ.get('CFLAGS', '-O3')
|
||||
CXXFLAGS = os.environ.get('CXXFLAGS', CFLAGS)
|
||||
LDFLAGS = os.environ.get('LDFLAGS', '')
|
||||
MFLAGS = os.environ.get('MFLAGS', '-j')
|
||||
|
||||
# Fuzzing environment variables
|
||||
LIB_FUZZING_ENGINE = os.environ.get('LIB_FUZZING_ENGINE', 'libregression.a')
|
||||
AFL_FUZZ = os.environ.get('AFL_FUZZ', 'afl-fuzz')
|
||||
DECODECORPUS = os.environ.get('DECODECORPUS',
|
||||
abs_join(FUZZ_DIR, '..', 'decodecorpus'))
|
||||
|
||||
# Sanitizer environment variables
|
||||
MSAN_EXTRA_CPPFLAGS = os.environ.get('MSAN_EXTRA_CPPFLAGS', '')
|
||||
MSAN_EXTRA_CFLAGS = os.environ.get('MSAN_EXTRA_CFLAGS', '')
|
||||
MSAN_EXTRA_CXXFLAGS = os.environ.get('MSAN_EXTRA_CXXFLAGS', '')
|
||||
MSAN_EXTRA_LDFLAGS = os.environ.get('MSAN_EXTRA_LDFLAGS', '')
|
||||
|
||||
|
||||
def create(r):
|
||||
d = os.path.abspath(r)
|
||||
if not os.path.isdir(d):
|
||||
os.mkdir(d)
|
||||
return d
|
||||
|
||||
|
||||
def check(r):
|
||||
d = os.path.abspath(r)
|
||||
if not os.path.isdir(d):
|
||||
return None
|
||||
return d
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def tmpdir():
|
||||
dirpath = tempfile.mkdtemp()
|
||||
try:
|
||||
yield dirpath
|
||||
finally:
|
||||
shutil.rmtree(dirpath, ignore_errors=True)
|
||||
|
||||
|
||||
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))
|
||||
|
||||
def set_sanitizer(sanitizer, default, san, nosan):
|
||||
if sanitizer in san and sanitizer in nosan:
|
||||
raise RuntimeError('-fno-sanitize={s} and -fsanitize={s} passed'.
|
||||
format(s=sanitizer))
|
||||
if sanitizer in san:
|
||||
return True
|
||||
if sanitizer in nosan:
|
||||
return False
|
||||
return default
|
||||
|
||||
san = set(san_flags.split(','))
|
||||
nosan = set(nosan_flags.split(','))
|
||||
|
||||
args.asan = set_sanitizer('address', args.asan, san, nosan)
|
||||
args.msan = set_sanitizer('memory', args.msan, san, nosan)
|
||||
args.ubsan = set_sanitizer('undefined', args.ubsan, san, nosan)
|
||||
|
||||
args.sanitize = args.asan or args.msan or args.ubsan
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def build_parser(args):
|
||||
description = """
|
||||
Cleans the repository and builds a fuzz target (or all).
|
||||
Many flags default to environment variables (default says $X='y').
|
||||
Options that aren't enabling features default to the correct values for
|
||||
zstd.
|
||||
Enable sanitizers with --enable-*san.
|
||||
For regression testing just build.
|
||||
For libFuzzer set LIB_FUZZING_ENGINE and pass --enable-coverage.
|
||||
For AFL set CC and CXX to AFL's compilers and set
|
||||
LIB_FUZZING_ENGINE='libregression.a'.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(prog=args.pop(0), description=description)
|
||||
parser.add_argument(
|
||||
'--lib-fuzzing-engine',
|
||||
dest='lib_fuzzing_engine',
|
||||
type=str,
|
||||
default=LIB_FUZZING_ENGINE,
|
||||
help=('The fuzzing engine to use e.g. /path/to/libFuzzer.a '
|
||||
"(default: $LIB_FUZZING_ENGINE='{})".format(LIB_FUZZING_ENGINE)))
|
||||
parser.add_argument(
|
||||
'--enable-coverage',
|
||||
dest='coverage',
|
||||
action='store_true',
|
||||
help='Enable coverage instrumentation (-fsanitize-coverage)')
|
||||
parser.add_argument(
|
||||
'--enable-asan', dest='asan', action='store_true', help='Enable UBSAN')
|
||||
parser.add_argument(
|
||||
'--enable-ubsan',
|
||||
dest='ubsan',
|
||||
action='store_true',
|
||||
help='Enable UBSAN')
|
||||
parser.add_argument(
|
||||
'--enable-ubsan-pointer-overflow',
|
||||
dest='ubsan_pointer_overflow',
|
||||
action='store_true',
|
||||
help='Enable UBSAN pointer overflow check (known failure)')
|
||||
parser.add_argument(
|
||||
'--enable-msan', dest='msan', action='store_true', help='Enable MSAN')
|
||||
parser.add_argument(
|
||||
'--enable-msan-track-origins', dest='msan_track_origins',
|
||||
action='store_true', help='Enable MSAN origin tracking')
|
||||
parser.add_argument(
|
||||
'--msan-extra-cppflags',
|
||||
dest='msan_extra_cppflags',
|
||||
type=str,
|
||||
default=MSAN_EXTRA_CPPFLAGS,
|
||||
help="Extra CPPFLAGS for MSAN (default: $MSAN_EXTRA_CPPFLAGS='{}')".
|
||||
format(MSAN_EXTRA_CPPFLAGS))
|
||||
parser.add_argument(
|
||||
'--msan-extra-cflags',
|
||||
dest='msan_extra_cflags',
|
||||
type=str,
|
||||
default=MSAN_EXTRA_CFLAGS,
|
||||
help="Extra CFLAGS for MSAN (default: $MSAN_EXTRA_CFLAGS='{}')".format(
|
||||
MSAN_EXTRA_CFLAGS))
|
||||
parser.add_argument(
|
||||
'--msan-extra-cxxflags',
|
||||
dest='msan_extra_cxxflags',
|
||||
type=str,
|
||||
default=MSAN_EXTRA_CXXFLAGS,
|
||||
help="Extra CXXFLAGS for MSAN (default: $MSAN_EXTRA_CXXFLAGS='{}')".
|
||||
format(MSAN_EXTRA_CXXFLAGS))
|
||||
parser.add_argument(
|
||||
'--msan-extra-ldflags',
|
||||
dest='msan_extra_ldflags',
|
||||
type=str,
|
||||
default=MSAN_EXTRA_LDFLAGS,
|
||||
help="Extra LDFLAGS for MSAN (default: $MSAN_EXTRA_LDFLAGS='{}')".
|
||||
format(MSAN_EXTRA_LDFLAGS))
|
||||
parser.add_argument(
|
||||
'--enable-sanitize-recover',
|
||||
dest='sanitize_recover',
|
||||
action='store_true',
|
||||
help='Non-fatal sanitizer errors where possible')
|
||||
parser.add_argument(
|
||||
'--debug',
|
||||
dest='debug',
|
||||
type=int,
|
||||
default=1,
|
||||
help='Set ZSTD_DEBUG (default: 1)')
|
||||
parser.add_argument(
|
||||
'--force-memory-access',
|
||||
dest='memory_access',
|
||||
type=int,
|
||||
default=0,
|
||||
help='Set MEM_FORCE_MEMORY_ACCESS (default: 0)')
|
||||
parser.add_argument(
|
||||
'--fuzz-rng-seed-size',
|
||||
dest='fuzz_rng_seed_size',
|
||||
type=int,
|
||||
default=4,
|
||||
help='Set FUZZ_RNG_SEED_SIZE (default: 4)')
|
||||
parser.add_argument(
|
||||
'--disable-fuzzing-mode',
|
||||
dest='fuzzing_mode',
|
||||
action='store_false',
|
||||
help='Do not define FUZZING_BUILD_MORE_UNSAFE_FOR_PRODUCTION')
|
||||
parser.add_argument(
|
||||
'--enable-stateful-fuzzing',
|
||||
dest='stateful_fuzzing',
|
||||
action='store_true',
|
||||
help='Reuse contexts between runs (makes reproduction impossible)')
|
||||
parser.add_argument(
|
||||
'--cc',
|
||||
dest='cc',
|
||||
type=str,
|
||||
default=CC,
|
||||
help="CC (default: $CC='{}')".format(CC))
|
||||
parser.add_argument(
|
||||
'--cxx',
|
||||
dest='cxx',
|
||||
type=str,
|
||||
default=CXX,
|
||||
help="CXX (default: $CXX='{}')".format(CXX))
|
||||
parser.add_argument(
|
||||
'--cppflags',
|
||||
dest='cppflags',
|
||||
type=str,
|
||||
default=CPPFLAGS,
|
||||
help="CPPFLAGS (default: $CPPFLAGS='{}')".format(CPPFLAGS))
|
||||
parser.add_argument(
|
||||
'--cflags',
|
||||
dest='cflags',
|
||||
type=str,
|
||||
default=CFLAGS,
|
||||
help="CFLAGS (default: $CFLAGS='{}')".format(CFLAGS))
|
||||
parser.add_argument(
|
||||
'--cxxflags',
|
||||
dest='cxxflags',
|
||||
type=str,
|
||||
default=CXXFLAGS,
|
||||
help="CXXFLAGS (default: $CXXFLAGS='{}')".format(CXXFLAGS))
|
||||
parser.add_argument(
|
||||
'--ldflags',
|
||||
dest='ldflags',
|
||||
type=str,
|
||||
default=LDFLAGS,
|
||||
help="LDFLAGS (default: $LDFLAGS='{}')".format(LDFLAGS))
|
||||
parser.add_argument(
|
||||
'--mflags',
|
||||
dest='mflags',
|
||||
type=str,
|
||||
default=MFLAGS,
|
||||
help="Extra Make flags (default: $MFLAGS='{}')".format(MFLAGS))
|
||||
parser.add_argument(
|
||||
'TARGET',
|
||||
nargs='*',
|
||||
type=str,
|
||||
help='Fuzz target(s) to build {{{}}}'.format(', '.join(ALL_TARGETS))
|
||||
)
|
||||
args = parser.parse_args(args)
|
||||
args = parse_env_flags(args, ' '.join(
|
||||
[args.cppflags, args.cflags, args.cxxflags, args.ldflags]))
|
||||
|
||||
# Check option sanitiy
|
||||
if args.msan and (args.asan or args.ubsan):
|
||||
raise RuntimeError('MSAN may not be used with any other sanitizers')
|
||||
if args.msan_track_origins and not args.msan:
|
||||
raise RuntimeError('--enable-msan-track-origins requires MSAN')
|
||||
if args.ubsan_pointer_overflow and not args.ubsan:
|
||||
raise RuntimeError('--enable-ubsan-pointer-overlow requires UBSAN')
|
||||
if args.sanitize_recover and not args.sanitize:
|
||||
raise RuntimeError('--enable-sanitize-recover but no sanitizers used')
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def build(args):
|
||||
try:
|
||||
args = build_parser(args)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
# The compilation flags we are setting
|
||||
targets = args.TARGET
|
||||
cc = args.cc
|
||||
cxx = args.cxx
|
||||
cppflags = [args.cppflags]
|
||||
cflags = [args.cflags]
|
||||
ldflags = [args.ldflags]
|
||||
cxxflags = [args.cxxflags]
|
||||
mflags = [args.mflags] if args.mflags else []
|
||||
# Flags to be added to both cflags and cxxflags
|
||||
common_flags = []
|
||||
|
||||
cppflags += [
|
||||
'-DZSTD_DEBUG={}'.format(args.debug),
|
||||
'-DMEM_FORCE_MEMORY_ACCESS={}'.format(args.memory_access),
|
||||
'-DFUZZ_RNG_SEED_SIZE={}'.format(args.fuzz_rng_seed_size),
|
||||
]
|
||||
|
||||
mflags += ['LIB_FUZZING_ENGINE={}'.format(args.lib_fuzzing_engine)]
|
||||
|
||||
# Set flags for options
|
||||
if args.coverage:
|
||||
common_flags += [
|
||||
'-fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp'
|
||||
]
|
||||
|
||||
if args.sanitize_recover:
|
||||
recover_flags = ['-fsanitize-recover=all']
|
||||
else:
|
||||
recover_flags = ['-fno-sanitize-recover=all']
|
||||
if args.sanitize:
|
||||
common_flags += recover_flags
|
||||
|
||||
if args.msan:
|
||||
msan_flags = ['-fsanitize=memory']
|
||||
if args.msan_track_origins:
|
||||
msan_flags += ['-fsanitize-memory-track-origins']
|
||||
common_flags += msan_flags
|
||||
# Append extra MSAN flags (it might require special setup)
|
||||
cppflags += [args.msan_extra_cppflags]
|
||||
cflags += [args.msan_extra_cflags]
|
||||
cxxflags += [args.msan_extra_cxxflags]
|
||||
ldflags += [args.msan_extra_ldflags]
|
||||
|
||||
if args.asan:
|
||||
common_flags += ['-fsanitize=address']
|
||||
|
||||
if args.ubsan:
|
||||
ubsan_flags = ['-fsanitize=undefined']
|
||||
if not args.ubsan_pointer_overflow:
|
||||
ubsan_flags += ['-fno-sanitize=pointer-overflow']
|
||||
common_flags += ubsan_flags
|
||||
|
||||
if args.stateful_fuzzing:
|
||||
cppflags += ['-DSTATEFUL_FUZZING']
|
||||
|
||||
if args.fuzzing_mode:
|
||||
cppflags += ['-DFUZZING_BUILD_MORE_UNSAFE_FOR_PRODUCTION']
|
||||
|
||||
if args.lib_fuzzing_engine == 'libregression.a':
|
||||
targets = ['libregression.a'] + targets
|
||||
|
||||
# Append the common flags
|
||||
cflags += common_flags
|
||||
cxxflags += common_flags
|
||||
|
||||
# Prepare the flags for Make
|
||||
cc_str = "CC={}".format(cc)
|
||||
cxx_str = "CXX={}".format(cxx)
|
||||
cppflags_str = "CPPFLAGS={}".format(' '.join(cppflags))
|
||||
cflags_str = "CFLAGS={}".format(' '.join(cflags))
|
||||
cxxflags_str = "CXXFLAGS={}".format(' '.join(cxxflags))
|
||||
ldflags_str = "LDFLAGS={}".format(' '.join(ldflags))
|
||||
|
||||
# Print the flags
|
||||
print('MFLAGS={}'.format(' '.join(mflags)))
|
||||
print(cc_str)
|
||||
print(cxx_str)
|
||||
print(cppflags_str)
|
||||
print(cflags_str)
|
||||
print(cxxflags_str)
|
||||
print(ldflags_str)
|
||||
|
||||
# Clean and build
|
||||
clean_cmd = ['make', 'clean'] + mflags
|
||||
print(' '.join(clean_cmd))
|
||||
subprocess.check_call(clean_cmd)
|
||||
build_cmd = [
|
||||
'make',
|
||||
cc_str,
|
||||
cxx_str,
|
||||
cppflags_str,
|
||||
cflags_str,
|
||||
cxxflags_str,
|
||||
ldflags_str,
|
||||
] + mflags + targets
|
||||
print(' '.join(build_cmd))
|
||||
subprocess.check_call(build_cmd)
|
||||
return 0
|
||||
|
||||
|
||||
def libfuzzer_parser(args):
|
||||
description = """
|
||||
Runs a libfuzzer binary.
|
||||
Passes all extra arguments to libfuzzer.
|
||||
The fuzzer should have been build with LIB_FUZZING_ENGINE pointing to
|
||||
libFuzzer.a.
|
||||
Generates output in the CORPORA directory, puts crashes in the ARTIFACT
|
||||
directory, and takes extra input from the SEED directory.
|
||||
To merge AFL's output pass the SEED as AFL's output directory and pass
|
||||
'-merge=1'.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(prog=args.pop(0), description=description)
|
||||
parser.add_argument(
|
||||
'--corpora',
|
||||
type=str,
|
||||
help='Override the default corpora dir (default: {})'.format(
|
||||
abs_join(CORPORA_DIR, 'TARGET')))
|
||||
parser.add_argument(
|
||||
'--artifact',
|
||||
type=str,
|
||||
help='Override the default artifact dir (default: {})'.format(
|
||||
abs_join(CORPORA_DIR, 'TARGET-crash')))
|
||||
parser.add_argument(
|
||||
'--seed',
|
||||
type=str,
|
||||
help='Override the default seed dir (default: {})'.format(
|
||||
abs_join(CORPORA_DIR, 'TARGET-seed')))
|
||||
parser.add_argument(
|
||||
'TARGET',
|
||||
type=str,
|
||||
help='Fuzz target(s) to build {{{}}}'.format(', '.join(TARGETS)))
|
||||
args, extra = parser.parse_known_args(args)
|
||||
args.extra = extra
|
||||
|
||||
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)
|
||||
|
||||
corpora = [create(args.corpora)]
|
||||
artifact = create(args.artifact)
|
||||
seed = check(args.seed)
|
||||
|
||||
corpora += [artifact]
|
||||
if seed is not None:
|
||||
corpora += [seed]
|
||||
|
||||
cmd = [target, '-artifact_prefix={}/'.format(artifact)]
|
||||
cmd += corpora + args.extra
|
||||
print(' '.join(cmd))
|
||||
subprocess.call(cmd)
|
||||
return 0
|
||||
|
||||
|
||||
def afl_parser(args):
|
||||
description = """
|
||||
Runs an afl-fuzz job.
|
||||
Passes all extra arguments to afl-fuzz.
|
||||
The fuzzer should have been built with CC/CXX set to the AFL compilers,
|
||||
and with LIB_FUZZING_ENGINE='libregression.a'.
|
||||
Takes input from CORPORA and writes output to OUTPUT.
|
||||
Uses AFL_FUZZ as the binary (set from flag or environment variable).
|
||||
"""
|
||||
parser = argparse.ArgumentParser(prog=args.pop(0), description=description)
|
||||
parser.add_argument(
|
||||
'--corpora',
|
||||
type=str,
|
||||
help='Override the default corpora dir (default: {})'.format(
|
||||
abs_join(CORPORA_DIR, 'TARGET')))
|
||||
parser.add_argument(
|
||||
'--output',
|
||||
type=str,
|
||||
help='Override the default AFL output dir (default: {})'.format(
|
||||
abs_join(CORPORA_DIR, 'TARGET-afl')))
|
||||
parser.add_argument(
|
||||
'--afl-fuzz',
|
||||
type=str,
|
||||
default=AFL_FUZZ,
|
||||
help='AFL_FUZZ (default: $AFL_FUZZ={})'.format(AFL_FUZZ))
|
||||
parser.add_argument(
|
||||
'TARGET',
|
||||
type=str,
|
||||
help='Fuzz target(s) to build {{{}}}'.format(', '.join(TARGETS)))
|
||||
args, extra = parser.parse_known_args(args)
|
||||
args.extra = extra
|
||||
|
||||
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.output:
|
||||
args.output = abs_join(CORPORA_DIR, '{}-afl'.format(args.TARGET))
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def afl(args):
|
||||
try:
|
||||
args = afl_parser(args)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
target = abs_join(FUZZ_DIR, args.TARGET)
|
||||
|
||||
corpora = create(args.corpora)
|
||||
output = create(args.output)
|
||||
|
||||
cmd = [args.afl_fuzz, '-i', corpora, '-o', output] + args.extra
|
||||
cmd += [target, '@@']
|
||||
print(' '.join(cmd))
|
||||
subprocess.call(cmd)
|
||||
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)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
for target in args.TARGET:
|
||||
corpora = create(abs_join(CORPORA_DIR, target))
|
||||
target = abs_join(FUZZ_DIR, target)
|
||||
cmd = [target, corpora]
|
||||
print(' '.join(cmd))
|
||||
subprocess.check_call(cmd)
|
||||
return 0
|
||||
|
||||
|
||||
def gen_parser(args):
|
||||
description = """
|
||||
Generate a seed corpus appropiate for TARGET with data generated with
|
||||
decodecorpus.
|
||||
The fuzz inputs are prepended with a seed before the zstd data, so the
|
||||
output of decodecorpus shouldn't be used directly.
|
||||
Generates NUMBER samples prepended with FUZZ_RNG_SEED_SIZE random bytes and
|
||||
puts the output in SEED.
|
||||
DECODECORPUS is the decodecorpus binary, and must already be built.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(prog=args.pop(0), description=description)
|
||||
parser.add_argument(
|
||||
'--number',
|
||||
'-n',
|
||||
type=int,
|
||||
default=100,
|
||||
help='Number of samples to generate')
|
||||
parser.add_argument(
|
||||
'--max-size-log',
|
||||
type=int,
|
||||
default=13,
|
||||
help='Maximum sample size to generate')
|
||||
parser.add_argument(
|
||||
'--seed',
|
||||
type=str,
|
||||
help='Override the default seed dir (default: {})'.format(
|
||||
abs_join(CORPORA_DIR, 'TARGET-seed')))
|
||||
parser.add_argument(
|
||||
'--decodecorpus',
|
||||
type=str,
|
||||
default=DECODECORPUS,
|
||||
help="decodecorpus binary (default: $DECODECORPUS='{}')".format(
|
||||
DECODECORPUS))
|
||||
parser.add_argument(
|
||||
'--fuzz-rng-seed-size',
|
||||
type=int,
|
||||
default=4,
|
||||
help="FUZZ_RNG_SEED_SIZE used for generate the samples (must match)"
|
||||
)
|
||||
parser.add_argument(
|
||||
'TARGET',
|
||||
type=str,
|
||||
help='Fuzz target(s) to build {{{}}}'.format(', '.join(TARGETS)))
|
||||
args, extra = parser.parse_known_args(args)
|
||||
args.extra = extra
|
||||
|
||||
if args.TARGET and args.TARGET not in TARGETS:
|
||||
raise RuntimeError('{} is not a valid target'.format(args.TARGET))
|
||||
|
||||
if not args.seed:
|
||||
args.seed = abs_join(CORPORA_DIR, '{}-seed'.format(args.TARGET))
|
||||
|
||||
if not os.path.isfile(args.decodecorpus):
|
||||
raise RuntimeError("{} is not a file run 'make -C {} decodecorpus'".
|
||||
format(args.decodecorpus, abs_join(FUZZ_DIR, '..')))
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def gen(args):
|
||||
try:
|
||||
args = gen_parser(args)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
|
||||
seed = create(args.seed)
|
||||
with tmpdir() as compressed:
|
||||
with tmpdir() as decompressed:
|
||||
cmd = [
|
||||
args.decodecorpus,
|
||||
'-n{}'.format(args.number),
|
||||
'-p{}/'.format(compressed),
|
||||
'-o{}'.format(decompressed),
|
||||
]
|
||||
|
||||
if 'block_' in args.TARGET:
|
||||
cmd += [
|
||||
'--gen-blocks',
|
||||
'--max-block-size-log={}'.format(args.max_size_log)
|
||||
]
|
||||
else:
|
||||
cmd += ['--max-content-size-log={}'.format(args.max_size_log)]
|
||||
|
||||
print(' '.join(cmd))
|
||||
subprocess.check_call(cmd)
|
||||
|
||||
if '_round_trip' in args.TARGET:
|
||||
print('using decompressed data in {}'.format(decompressed))
|
||||
samples = decompressed
|
||||
elif '_decompress' in args.TARGET:
|
||||
print('using compressed data in {}'.format(compressed))
|
||||
samples = compressed
|
||||
|
||||
# Copy the samples over and prepend the RNG seeds
|
||||
for name in os.listdir(samples):
|
||||
samplename = abs_join(samples, name)
|
||||
outname = abs_join(seed, name)
|
||||
rng_seed = os.urandom(args.fuzz_rng_seed_size)
|
||||
with open(samplename, 'rb') as sample:
|
||||
with open(outname, 'wb') as out:
|
||||
out.write(rng_seed)
|
||||
CHUNK_SIZE = 131072
|
||||
chunk = sample.read(CHUNK_SIZE)
|
||||
while len(chunk) > 0:
|
||||
out.write(chunk)
|
||||
chunk = sample.read(CHUNK_SIZE)
|
||||
return 0
|
||||
|
||||
|
||||
def short_help(args):
|
||||
name = args[0]
|
||||
print("Usage: {} [OPTIONS] COMMAND [ARGS]...\n".format(name))
|
||||
|
||||
|
||||
def help(args):
|
||||
short_help(args)
|
||||
print("\tfuzzing helpers (select a command and pass -h for help)\n")
|
||||
print("Options:")
|
||||
print("\t-h, --help\tPrint this message")
|
||||
print("")
|
||||
print("Commands:")
|
||||
print("\tbuild\t\tBuild a fuzzer")
|
||||
print("\tlibfuzzer\tRun a libFuzzer fuzzer")
|
||||
print("\tafl\t\tRun an AFL fuzzer")
|
||||
print("\tregression\tRun a regression test")
|
||||
print("\tgen\t\tGenerate a seed corpus for a fuzzer")
|
||||
|
||||
|
||||
def main():
|
||||
args = sys.argv
|
||||
if len(args) < 2:
|
||||
help(args)
|
||||
return 1
|
||||
if args[1] == '-h' or args[1] == '--help' or args[1] == '-H':
|
||||
help(args)
|
||||
return 1
|
||||
command = args.pop(1)
|
||||
args[0] = "{} {}".format(args[0], command)
|
||||
if command == "build":
|
||||
return build(args)
|
||||
if command == "libfuzzer":
|
||||
return libfuzzer(args)
|
||||
if command == "regression":
|
||||
return regression(args)
|
||||
if command == "afl":
|
||||
return afl(args)
|
||||
if command == "gen":
|
||||
return gen(args)
|
||||
short_help(args)
|
||||
print("Error: No such command {} (pass -h for help)".format(command))
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
+16
-38
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -16,14 +16,8 @@
|
||||
|
||||
#include "fuzz.h"
|
||||
#include "xxhash.h"
|
||||
#include "zstd.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
@@ -40,8 +34,6 @@ extern "C" {
|
||||
__LINE__, FUZZ_QUOTE(cond), (msg)), \
|
||||
abort()))
|
||||
#define FUZZ_ASSERT(cond) FUZZ_ASSERT_MSG((cond), "");
|
||||
#define FUZZ_ZASSERT(code) \
|
||||
FUZZ_ASSERT_MSG(!ZSTD_isError(code), ZSTD_getErrorName(code))
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define FUZZ_STATIC static __inline __attribute__((unused))
|
||||
@@ -56,37 +48,23 @@ extern "C" {
|
||||
|
||||
/**
|
||||
* Determininistically constructs a seed based on the fuzz input.
|
||||
* Consumes up to the first FUZZ_RNG_SEED_SIZE bytes of the input.
|
||||
* Only looks at the first FUZZ_RNG_SEED_SIZE bytes of the input.
|
||||
*/
|
||||
FUZZ_STATIC uint32_t FUZZ_seed(uint8_t const **src, size_t* size) {
|
||||
uint8_t const *data = *src;
|
||||
size_t const toHash = MIN(FUZZ_RNG_SEED_SIZE, *size);
|
||||
*size -= toHash;
|
||||
*src += toHash;
|
||||
return XXH32(data, toHash, 0);
|
||||
FUZZ_STATIC uint32_t FUZZ_seed(const uint8_t *src, size_t size) {
|
||||
size_t const toHash = MIN(FUZZ_RNG_SEED_SIZE, size);
|
||||
return XXH32(src, toHash, 0);
|
||||
}
|
||||
|
||||
#define FUZZ_rotl32(x, r) (((x) << (r)) | ((x) >> (32 - (r))))
|
||||
|
||||
FUZZ_STATIC uint32_t FUZZ_rand(uint32_t *state) {
|
||||
static const uint32_t prime1 = 2654435761U;
|
||||
static const uint32_t prime2 = 2246822519U;
|
||||
uint32_t rand32 = *state;
|
||||
rand32 *= prime1;
|
||||
rand32 += prime2;
|
||||
rand32 = FUZZ_rotl32(rand32, 13);
|
||||
*state = rand32;
|
||||
return rand32 >> 5;
|
||||
static const uint32_t prime1 = 2654435761U;
|
||||
static const uint32_t prime2 = 2246822519U;
|
||||
uint32_t rand32 = *state;
|
||||
rand32 *= prime1;
|
||||
rand32 += prime2;
|
||||
rand32 = FUZZ_rotl32(rand32, 13);
|
||||
*state = rand32;
|
||||
return rand32 >> 5;
|
||||
}
|
||||
|
||||
/* Returns a random numer in the range [min, max]. */
|
||||
FUZZ_STATIC uint32_t FUZZ_rand32(uint32_t *state, uint32_t min, uint32_t max) {
|
||||
uint32_t random = FUZZ_rand(state);
|
||||
return min + (random % (max - min + 1));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "fuzz.h"
|
||||
@@ -29,11 +29,9 @@ int main(int argc, char const **argv) {
|
||||
#ifdef UTIL_HAS_CREATEFILELIST
|
||||
files = UTIL_createFileList(files, numFiles, &fileNamesBuf, &numFiles,
|
||||
kFollowLinks);
|
||||
if (!files)
|
||||
numFiles = 0;
|
||||
FUZZ_ASSERT(files);
|
||||
#endif
|
||||
if (numFiles == 0)
|
||||
fprintf(stderr, "WARNING: No files passed to %s\n", argv[0]);
|
||||
|
||||
for (i = 0; i < numFiles; ++i) {
|
||||
char const *fileName = files[i];
|
||||
size_t const fileSize = UTIL_getFileSize(fileName);
|
||||
@@ -41,7 +39,7 @@ int main(int argc, char const **argv) {
|
||||
FILE *file;
|
||||
|
||||
/* Check that it is a regular file, and that the fileSize is valid */
|
||||
FUZZ_ASSERT_MSG(UTIL_isRegularFile(fileName), fileName);
|
||||
FUZZ_ASSERT_MSG(UTIL_isRegFile(fileName), fileName);
|
||||
FUZZ_ASSERT_MSG(fileSize <= kMaxFileSize, fileName);
|
||||
/* Ensure we have a large enough buffer allocated */
|
||||
if (fileSize > bufferSize) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
/**
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -24,10 +24,7 @@ static size_t bufSize = 0;
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
size_t neededBufSize;
|
||||
|
||||
FUZZ_seed(&src, &size);
|
||||
neededBufSize = MAX(20 * size, (size_t)256 << 10);
|
||||
size_t const neededBufSize = MAX(20 * size, (size_t)256 << 10);
|
||||
|
||||
/* Allocate all buffers and contexts if not already allocated */
|
||||
if (neededBufSize > bufSize) {
|
||||
@@ -42,7 +39,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
}
|
||||
ZSTD_decompressDCtx(dctx, rBuf, neededBufSize, src, size);
|
||||
|
||||
#ifndef STATEFUL_FUZZING
|
||||
#ifndef STATEFULL_FUZZING
|
||||
ZSTD_freeDCtx(dctx); dctx = NULL;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -12,14 +12,12 @@
|
||||
* compares the result with the original, and calls abort() on corruption.
|
||||
*/
|
||||
|
||||
#define ZSTD_STATIC_LINKING_ONLY
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd_helpers.h"
|
||||
#include "zstd.h"
|
||||
|
||||
static const int kMaxClevel = 19;
|
||||
|
||||
@@ -34,36 +32,21 @@ static size_t roundTripTest(void *result, size_t resultCapacity,
|
||||
void *compressed, size_t compressedCapacity,
|
||||
const void *src, size_t srcSize)
|
||||
{
|
||||
size_t cSize;
|
||||
if (FUZZ_rand(&seed) & 1) {
|
||||
ZSTD_inBuffer in = {src, srcSize, 0};
|
||||
ZSTD_outBuffer out = {compressed, compressedCapacity, 0};
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
return ZSTD_decompressDCtx(dctx, result, resultCapacity, compressed, cSize);
|
||||
int const cLevel = FUZZ_rand(&seed) % kMaxClevel;
|
||||
size_t const cSize = ZSTD_compressCCtx(cctx, compressed, compressedCapacity,
|
||||
src, srcSize, cLevel);
|
||||
if (ZSTD_isError(cSize)) {
|
||||
fprintf(stderr, "Compression error: %s\n", ZSTD_getErrorName(cSize));
|
||||
return cSize;
|
||||
}
|
||||
return ZSTD_decompressDCtx(dctx, result, resultCapacity, compressed, cSize);
|
||||
}
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
size_t neededBufSize;
|
||||
size_t const neededBufSize = ZSTD_compressBound(size);
|
||||
|
||||
seed = FUZZ_seed(&src, &size);
|
||||
neededBufSize = ZSTD_compressBound(size);
|
||||
seed = FUZZ_seed(src, size);
|
||||
|
||||
/* Allocate all buffers and contexts if not already allocated */
|
||||
if (neededBufSize > bufSize) {
|
||||
@@ -90,7 +73,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
|
||||
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
|
||||
}
|
||||
#ifndef STATEFUL_FUZZING
|
||||
#ifndef STATEFULL_FUZZING
|
||||
ZSTD_freeCCtx(cctx); cctx = NULL;
|
||||
ZSTD_freeDCtx(dctx); dctx = NULL;
|
||||
#endif
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
/**
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd.h"
|
||||
|
||||
static size_t const kBufSize = ZSTD_BLOCKSIZE_MAX;
|
||||
static size_t const kBufSize = ZSTD_BLOCKSIZE_ABSOLUTEMAX;
|
||||
|
||||
static ZSTD_DStream *dstream = NULL;
|
||||
static void* buf = NULL;
|
||||
@@ -51,7 +51,7 @@ static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size)
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
seed = FUZZ_seed(&src, &size);
|
||||
seed = FUZZ_seed(src, size);
|
||||
|
||||
/* Allocate all buffers and contexts if not already allocated */
|
||||
if (!buf) {
|
||||
@@ -78,7 +78,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
}
|
||||
|
||||
error:
|
||||
#ifndef STATEFUL_FUZZING
|
||||
#ifndef STATEFULL_FUZZING
|
||||
ZSTD_freeDStream(dstream); dstream = NULL;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -12,16 +12,16 @@
|
||||
* compares the result with the original, and calls abort() on corruption.
|
||||
*/
|
||||
|
||||
#define ZSTD_STATIC_LINKING_ONLY
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd_helpers.h"
|
||||
#include "zstd.h"
|
||||
|
||||
ZSTD_CCtx *cctx = NULL;
|
||||
static const int kMaxClevel = 19;
|
||||
|
||||
static ZSTD_CStream *cstream = NULL;
|
||||
static ZSTD_DCtx *dctx = NULL;
|
||||
static uint8_t* cBuf = NULL;
|
||||
static uint8_t* rBuf = NULL;
|
||||
@@ -30,99 +30,93 @@ static uint32_t seed;
|
||||
|
||||
static ZSTD_outBuffer makeOutBuffer(uint8_t *dst, size_t capacity)
|
||||
{
|
||||
ZSTD_outBuffer buffer = { dst, 0, 0 };
|
||||
ZSTD_outBuffer buffer = { dst, 0, 0 };
|
||||
|
||||
FUZZ_ASSERT(capacity > 0);
|
||||
buffer.size = (FUZZ_rand(&seed) % capacity) + 1;
|
||||
FUZZ_ASSERT(buffer.size <= capacity);
|
||||
FUZZ_ASSERT(capacity > 0);
|
||||
buffer.size = (FUZZ_rand(&seed) % capacity) + 1;
|
||||
FUZZ_ASSERT(buffer.size <= capacity);
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size)
|
||||
{
|
||||
ZSTD_inBuffer buffer = { *src, 0, 0 };
|
||||
ZSTD_inBuffer buffer = { *src, 0, 0 };
|
||||
|
||||
FUZZ_ASSERT(*size > 0);
|
||||
buffer.size = (FUZZ_rand(&seed) % *size) + 1;
|
||||
FUZZ_ASSERT(buffer.size <= *size);
|
||||
*src += buffer.size;
|
||||
*size -= buffer.size;
|
||||
FUZZ_ASSERT(*size > 0);
|
||||
buffer.size = (FUZZ_rand(&seed) % *size) + 1;
|
||||
FUZZ_ASSERT(buffer.size <= *size);
|
||||
*src += buffer.size;
|
||||
*size -= buffer.size;
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static size_t compress(uint8_t *dst, size_t capacity,
|
||||
const uint8_t *src, size_t srcSize)
|
||||
{
|
||||
int cLevel = FUZZ_rand(&seed) % kMaxClevel;
|
||||
size_t dstSize = 0;
|
||||
ZSTD_CCtx_reset(cctx);
|
||||
FUZZ_setRandomParameters(cctx, &seed);
|
||||
FUZZ_ASSERT(!ZSTD_isError(ZSTD_initCStream(cstream, cLevel)));
|
||||
|
||||
while (srcSize > 0) {
|
||||
ZSTD_inBuffer in = makeInBuffer(&src, &srcSize);
|
||||
/* Mode controls the action. If mode == -1 we pick a new mode */
|
||||
int mode = -1;
|
||||
while (in.pos < in.size) {
|
||||
ZSTD_outBuffer out = makeOutBuffer(dst, capacity);
|
||||
/* Previous action finished, pick a new mode. */
|
||||
if (mode == -1) mode = FUZZ_rand(&seed) % 10;
|
||||
switch (mode) {
|
||||
case 0: /* fall-though */
|
||||
case 1: /* fall-though */
|
||||
case 2: {
|
||||
size_t const ret =
|
||||
ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_flush);
|
||||
FUZZ_ZASSERT(ret);
|
||||
if (ret == 0)
|
||||
mode = -1;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
size_t ret =
|
||||
ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end);
|
||||
FUZZ_ZASSERT(ret);
|
||||
/* Reset the compressor when the frame is finished */
|
||||
if (ret == 0) {
|
||||
ZSTD_CCtx_reset(cctx);
|
||||
FUZZ_setRandomParameters(cctx, &seed);
|
||||
mode = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
size_t const ret =
|
||||
ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_continue);
|
||||
FUZZ_ZASSERT(ret);
|
||||
ZSTD_outBuffer out = makeOutBuffer(dst, capacity);
|
||||
/* Previous action finished, pick a new mode. */
|
||||
if (mode == -1) mode = FUZZ_rand(&seed) % 10;
|
||||
switch (mode) {
|
||||
case 0: /* fall-though */
|
||||
case 1: /* fall-though */
|
||||
case 2: {
|
||||
size_t const ret = ZSTD_flushStream(cstream, &out);
|
||||
FUZZ_ASSERT_MSG(!ZSTD_isError(ret), ZSTD_getErrorName(ret));
|
||||
if (ret == 0) mode = -1;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
size_t ret = ZSTD_endStream(cstream, &out);
|
||||
FUZZ_ASSERT_MSG(!ZSTD_isError(ret), ZSTD_getErrorName(ret));
|
||||
/* Reset the compressor when the frame is finished */
|
||||
if (ret == 0) {
|
||||
cLevel = FUZZ_rand(&seed) % kMaxClevel;
|
||||
ret = ZSTD_initCStream(cstream, cLevel);
|
||||
FUZZ_ASSERT(!ZSTD_isError(ret));
|
||||
mode = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
dst += out.pos;
|
||||
dstSize += out.pos;
|
||||
capacity -= out.pos;
|
||||
default: {
|
||||
size_t const ret = ZSTD_compressStream(cstream, &out, &in);
|
||||
FUZZ_ASSERT_MSG(!ZSTD_isError(ret), ZSTD_getErrorName(ret));
|
||||
mode = -1;
|
||||
}
|
||||
}
|
||||
dst += out.pos;
|
||||
dstSize += out.pos;
|
||||
capacity -= out.pos;
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
ZSTD_inBuffer in = {NULL, 0, 0};
|
||||
ZSTD_outBuffer out = makeOutBuffer(dst, capacity);
|
||||
size_t const ret = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end);
|
||||
FUZZ_ZASSERT(ret);
|
||||
size_t const ret = ZSTD_endStream(cstream, &out);
|
||||
FUZZ_ASSERT_MSG(!ZSTD_isError(ret), ZSTD_getErrorName(ret));
|
||||
|
||||
dst += out.pos;
|
||||
dstSize += out.pos;
|
||||
capacity -= out.pos;
|
||||
if (ret == 0)
|
||||
break;
|
||||
if (ret == 0) break;
|
||||
}
|
||||
return dstSize;
|
||||
}
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
size_t neededBufSize;
|
||||
size_t const neededBufSize = ZSTD_compressBound(size) * 2;
|
||||
|
||||
seed = FUZZ_seed(&src, &size);
|
||||
neededBufSize = ZSTD_compressBound(size) * 2;
|
||||
seed = FUZZ_seed(src, size);
|
||||
|
||||
/* Allocate all buffers and contexts if not already allocated */
|
||||
if (neededBufSize > bufSize) {
|
||||
@@ -133,9 +127,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
bufSize = neededBufSize;
|
||||
FUZZ_ASSERT(cBuf && rBuf);
|
||||
}
|
||||
if (!cctx) {
|
||||
cctx = ZSTD_createCCtx();
|
||||
FUZZ_ASSERT(cctx);
|
||||
if (!cstream) {
|
||||
cstream = ZSTD_createCStream();
|
||||
FUZZ_ASSERT(cstream);
|
||||
}
|
||||
if (!dctx) {
|
||||
dctx = ZSTD_createDCtx();
|
||||
@@ -151,8 +145,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
|
||||
}
|
||||
|
||||
#ifndef STATEFUL_FUZZING
|
||||
ZSTD_freeCCtx(cctx); cctx = NULL;
|
||||
#ifndef STATEFULL_FUZZING
|
||||
ZSTD_freeCStream(cstream); cstream = NULL;
|
||||
ZSTD_freeDCtx(dctx); dctx = NULL;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
*/
|
||||
|
||||
#define ZSTD_STATIC_LINKING_ONLY
|
||||
|
||||
#include "zstd_helpers.h"
|
||||
#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));
|
||||
}
|
||||
|
||||
void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, 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 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_ldmMinMatch, ZSTD_LDM_MINMATCH_MIN,
|
||||
ZSTD_LDM_MINMATCH_MAX, state);
|
||||
setRand(cctx, ZSTD_p_ldmBucketSizeLog, 0, ZSTD_LDM_BUCKETSIZELOG_MAX,
|
||||
state);
|
||||
setRand(cctx, ZSTD_p_ldmHashEveryLog, 0,
|
||||
ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN, state);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper functions for fuzzing.
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_HELPERS_H
|
||||
#define ZSTD_HELPERS_H
|
||||
|
||||
#include "zstd.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, uint32_t *state);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZSTD_HELPERS_H */
|
||||
+11
-41
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2015-present, Yann Collet, Facebook, Inc.
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
|
||||
@@ -599,10 +598,10 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(4, "test%3i : decompress with static DDict : ", testNb++);
|
||||
{ size_t const ddictBufferSize = ZSTD_estimateDDictSize(dictSize, ZSTD_dlm_byCopy);
|
||||
{ size_t const ddictBufferSize = ZSTD_estimateDDictSize(dictSize, 0);
|
||||
void* ddictBuffer = malloc(ddictBufferSize);
|
||||
if (ddictBuffer == NULL) goto _output_error;
|
||||
{ ZSTD_DDict* const ddict = ZSTD_initStaticDDict(ddictBuffer, ddictBufferSize, CNBuffer, dictSize, ZSTD_dlm_byCopy);
|
||||
{ ZSTD_DDict* const ddict = ZSTD_initStaticDDict(ddictBuffer, ddictBufferSize, CNBuffer, dictSize, 0);
|
||||
size_t const r = ZSTD_decompress_usingDDict(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize, ddict);
|
||||
if (r != CNBuffSize - dictSize) goto _output_error;
|
||||
}
|
||||
@@ -688,14 +687,14 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
|
||||
DISPLAYLEVEL(4, "test%3i : estimate CDict size : ", testNb++);
|
||||
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
||||
size_t const estimatedSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byRef);
|
||||
size_t const estimatedSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, 1 /*byReference*/);
|
||||
DISPLAYLEVEL(4, "OK : %u \n", (U32)estimatedSize);
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(4, "test%3i : compress with CDict ", testNb++);
|
||||
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize,
|
||||
ZSTD_dlm_byRef, ZSTD_dm_auto,
|
||||
1 /* byReference */, ZSTD_dm_auto,
|
||||
cParams, ZSTD_defaultCMem);
|
||||
DISPLAYLEVEL(4, "(size : %u) : ", (U32)ZSTD_sizeof_CDict(cdict));
|
||||
cSize = ZSTD_compress_usingCDict(cctx, compressedBuffer, compressedBufferSize,
|
||||
@@ -721,12 +720,12 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
|
||||
DISPLAYLEVEL(4, "test%3i : compress with static CDict : ", testNb++);
|
||||
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
||||
size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
|
||||
size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, 0);
|
||||
void* const cdictBuffer = malloc(cdictSize);
|
||||
if (cdictBuffer==NULL) goto _output_error;
|
||||
{ ZSTD_CDict* const cdict = ZSTD_initStaticCDict(cdictBuffer, cdictSize,
|
||||
dictBuffer, dictSize,
|
||||
ZSTD_dlm_byCopy, ZSTD_dm_auto,
|
||||
0 /* by Reference */, ZSTD_dm_auto,
|
||||
cParams);
|
||||
if (cdict == NULL) {
|
||||
DISPLAY("ZSTD_initStaticCDict failed ");
|
||||
@@ -746,7 +745,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
DISPLAYLEVEL(4, "test%3i : ZSTD_compress_usingCDict_advanced, no contentSize, no dictID : ", testNb++);
|
||||
{ ZSTD_frameParameters const fParams = { 0 /* frameSize */, 1 /* checksum */, 1 /* noDictID*/ };
|
||||
ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dm_auto, cParams, ZSTD_defaultCMem);
|
||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize, 1 /*byRef*/, ZSTD_dm_auto, cParams, ZSTD_defaultCMem);
|
||||
cSize = ZSTD_compress_usingCDict_advanced(cctx, compressedBuffer, compressedBufferSize,
|
||||
CNBuffer, CNBuffSize, cdict, fParams);
|
||||
ZSTD_freeCDict(cdict);
|
||||
@@ -797,7 +796,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
|
||||
DISPLAYLEVEL(4, "test%3i : Building cdict w/ ZSTD_dm_fullDict on a good dictionary : ", testNb++);
|
||||
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dm_fullDict, cParams, ZSTD_defaultCMem);
|
||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize, 1 /*byRef*/, ZSTD_dm_fullDict, cParams, ZSTD_defaultCMem);
|
||||
if (cdict==NULL) goto _output_error;
|
||||
ZSTD_freeCDict(cdict);
|
||||
}
|
||||
@@ -805,32 +804,12 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
|
||||
DISPLAYLEVEL(4, "test%3i : Building cdict w/ ZSTD_dm_fullDict on a rawContent (must fail) : ", testNb++);
|
||||
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize);
|
||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced((const char*)dictBuffer+1, dictSize-1, ZSTD_dlm_byRef, ZSTD_dm_fullDict, cParams, ZSTD_defaultCMem);
|
||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced((const char*)dictBuffer+1, dictSize-1, 1 /*byRef*/, ZSTD_dm_fullDict, cParams, ZSTD_defaultCMem);
|
||||
if (cdict!=NULL) goto _output_error;
|
||||
ZSTD_freeCDict(cdict);
|
||||
}
|
||||
DISPLAYLEVEL(4, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(4, "test%3i : Loading rawContent starting with dict header w/ ZSTD_dm_auto should fail", testNb++);
|
||||
{
|
||||
size_t ret;
|
||||
MEM_writeLE32((char*)dictBuffer+2, ZSTD_MAGIC_DICTIONARY);
|
||||
ret = ZSTD_CCtx_loadDictionary_advanced(
|
||||
cctx, (const char*)dictBuffer+2, dictSize-2, ZSTD_dlm_byRef, ZSTD_dm_auto);
|
||||
if (!ZSTD_isError(ret)) goto _output_error;
|
||||
}
|
||||
DISPLAYLEVEL(4, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(4, "test%3i : Loading rawContent starting with dict header w/ ZSTD_dm_rawContent should pass", testNb++);
|
||||
{
|
||||
size_t ret;
|
||||
MEM_writeLE32((char*)dictBuffer+2, ZSTD_MAGIC_DICTIONARY);
|
||||
ret = ZSTD_CCtx_loadDictionary_advanced(
|
||||
cctx, (const char*)dictBuffer+2, dictSize-2, ZSTD_dlm_byRef, ZSTD_dm_rawContent);
|
||||
if (ZSTD_isError(ret)) goto _output_error;
|
||||
}
|
||||
DISPLAYLEVEL(4, "OK \n");
|
||||
|
||||
ZSTD_freeCCtx(cctx);
|
||||
free(dictBuffer);
|
||||
free(samplesSizes);
|
||||
@@ -1355,6 +1334,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
|
||||
}
|
||||
CHECK_Z( ZSTD_copyCCtx(ctx, refCtx, 0) );
|
||||
}
|
||||
ZSTD_setCCtxParameter(ctx, ZSTD_p_forceWindow, FUZ_rand(&lseed) & 1);
|
||||
|
||||
{ U32 const nbChunks = (FUZ_rand(&lseed) & 127) + 2;
|
||||
U32 n;
|
||||
@@ -1384,16 +1364,6 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
|
||||
}
|
||||
|
||||
/* streaming decompression test */
|
||||
/* ensure memory requirement is good enough (should always be true) */
|
||||
{ ZSTD_frameHeader zfh;
|
||||
CHECK( ZSTD_getFrameHeader(&zfh, cBuffer, ZSTD_frameHeaderSize_max),
|
||||
"ZSTD_getFrameHeader(): error retrieving frame information");
|
||||
{ size_t const roundBuffSize = ZSTD_decodingBufferSize_min(zfh.windowSize, zfh.frameContentSize);
|
||||
CHECK_Z(roundBuffSize);
|
||||
CHECK((roundBuffSize > totalTestSize) && (zfh.frameContentSize!=ZSTD_CONTENTSIZE_UNKNOWN),
|
||||
"ZSTD_decodingBufferSize_min() requires more memory (%u) than necessary (%u)",
|
||||
(U32)roundBuffSize, (U32)totalTestSize );
|
||||
} }
|
||||
if (dictSize<8) dictSize=0, dict=NULL; /* disable dictionary */
|
||||
CHECK_Z( ZSTD_decompressBegin_usingDict(dctx, dict, dictSize) );
|
||||
totalCSize = 0;
|
||||
|
||||
+5
-5
@@ -1,10 +1,10 @@
|
||||
# ################################################################
|
||||
# Copyright (c) 2017-present, Facebook, Inc.
|
||||
# Copyright (c) 2017-present, Yann Collet, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# 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.
|
||||
# ################################################################
|
||||
|
||||
PRGDIR = ../../programs
|
||||
@@ -12,7 +12,7 @@ VOID = /dev/null
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: all
|
||||
#all: test-gzip-env
|
||||
#all: test-gzip-env
|
||||
all: test-helin-segv test-hufts test-keep test-list test-memcpy-abuse test-mixed
|
||||
all: test-null-suffix-clobber test-stdin test-trailing-nul test-unpack-invalid
|
||||
all: test-zdiff test-zgrep-context test-zgrep-f test-zgrep-signal test-znew-k test-z-suffix
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
+1
-2
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2017-present, Yann Collet, Facebook, Inc.
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
+3
-4
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2015-present, Yann Collet, Facebook, Inc.
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
|
||||
@@ -391,8 +390,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_advanced(params);
|
||||
size_t O_CMemUsed = (1 << winners[cLevel].params.windowLog) + ZSTD_estimateCCtxSize_advanced(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);
|
||||
|
||||
|
||||
+1
-27
@@ -161,8 +161,6 @@ roundTripTest -g512K
|
||||
roundTripTest -g512K " --zstd=slen=3,tlen=48,strat=6"
|
||||
roundTripTest -g512K " --zstd=strat=6,wlog=23,clog=23,hlog=22,slog=6"
|
||||
roundTripTest -g512K " --zstd=windowLog=23,chainLog=23,hashLog=22,searchLog=6,searchLength=3,targetLength=48,strategy=6"
|
||||
roundTripTest -g512K " --long --zstd=ldmHashLog=20,ldmSearchLength=64,ldmBucketSizeLog=1,ldmHashEveryLog=7"
|
||||
roundTripTest -g512K " --long --zstd=ldmhlog=20,ldmslen=64,ldmblog=1,ldmhevery=7"
|
||||
roundTripTest -g512K 19
|
||||
|
||||
|
||||
@@ -293,10 +291,8 @@ $ECHO "- Create dictionary with wrong dictID parameter order (must fail)"
|
||||
$ZSTD --train *.c ../programs/*.c --dictID -o 1 tmpDict1 && die "wrong order : --dictID must be followed by argument "
|
||||
$ECHO "- Create dictionary with size limit"
|
||||
$ZSTD --train *.c ../programs/*.c -o tmpDict2 --maxdict=4K -v
|
||||
$ECHO "- Create dictionary with small size limit"
|
||||
$ZSTD --train *.c ../programs/*.c -o tmpDict3 --maxdict=1K -v
|
||||
$ECHO "- Create dictionary with wrong parameter order (must fail)"
|
||||
$ZSTD --train *.c ../programs/*.c -o tmpDict3 --maxdict -v 4K && die "wrong order : --maxdict must be followed by argument "
|
||||
$ZSTD --train *.c ../programs/*.c -o tmpDict2 --maxdict -v 4K && die "wrong order : --maxdict must be followed by argument "
|
||||
$ECHO "- Compress without dictID"
|
||||
$ZSTD -f tmp -D tmpDict1 --no-dictID
|
||||
$ZSTD -d tmp.zst -D tmpDict -fo result
|
||||
@@ -555,15 +551,6 @@ roundTripTest -g516K 19 # btopt
|
||||
|
||||
fileRoundTripTest -g500K
|
||||
|
||||
$ECHO "\n**** zstd long distance matching round-trip tests **** "
|
||||
roundTripTest -g0 "2 --long"
|
||||
roundTripTest -g1000K "1 --long"
|
||||
roundTripTest -g517K "6 --long"
|
||||
roundTripTest -g516K "16 --long"
|
||||
roundTripTest -g518K "19 --long"
|
||||
fileRoundTripTest -g5M "3 --long"
|
||||
|
||||
|
||||
if [ -n "$hasMT" ]
|
||||
then
|
||||
$ECHO "\n**** zstdmt round-trip tests **** "
|
||||
@@ -571,9 +558,6 @@ then
|
||||
roundTripTest -g8M "3 -T2"
|
||||
roundTripTest -g8000K "2 --threads=2"
|
||||
fileRoundTripTest -g4M "19 -T2 -B1M"
|
||||
|
||||
$ECHO "\n**** zstdmt long distance matching round-trip tests **** "
|
||||
roundTripTest -g8M "3 --long -T2"
|
||||
else
|
||||
$ECHO "\n**** no multithreading, skipping zstdmt tests **** "
|
||||
fi
|
||||
@@ -662,15 +646,6 @@ roundTripTest -g6000000000 -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 -g18000001 -P80 "18 --long"
|
||||
fileRoundTripTest -g4100M -P99 "1 --long"
|
||||
|
||||
|
||||
if [ -n "$hasMT" ]
|
||||
then
|
||||
$ECHO "\n**** zstdmt long round-trip tests **** "
|
||||
@@ -678,7 +653,6 @@ then
|
||||
roundTripTest -g6000000000 -P99 "1 -T2"
|
||||
roundTripTest -g1500000000 -P97 "1 -T999"
|
||||
fileRoundTripTest -g4195M -P98 " -T0"
|
||||
roundTripTest -g1500000000 -P97 "1 --long -T999"
|
||||
else
|
||||
$ECHO "\n**** no multithreading, skipping zstdmt tests **** "
|
||||
fi
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
+14
-69
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -21,12 +20,9 @@
|
||||
#include <stddef.h> /* size_t */
|
||||
#include <stdlib.h> /* malloc, free, exit */
|
||||
#include <stdio.h> /* fprintf */
|
||||
#include <string.h> /* strcmp */
|
||||
#include <sys/types.h> /* stat */
|
||||
#include <sys/stat.h> /* stat */
|
||||
#include "xxhash.h"
|
||||
|
||||
#define ZSTD_STATIC_LINKING_ONLY
|
||||
#include "zstd.h"
|
||||
|
||||
/*===========================================
|
||||
@@ -34,24 +30,6 @@
|
||||
*==========================================*/
|
||||
#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
|
||||
|
||||
static void crash(int errorCode){
|
||||
/* abort if AFL/libfuzzer, exit otherwise */
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* could also use __AFL_COMPILER */
|
||||
abort();
|
||||
#else
|
||||
exit(errorCode);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define CHECK_Z(f) { \
|
||||
size_t const err = f; \
|
||||
if (ZSTD_isError(err)) { \
|
||||
fprintf(stderr, \
|
||||
"Error=> %s: %s", \
|
||||
#f, ZSTD_getErrorName(err)); \
|
||||
crash(1); \
|
||||
} }
|
||||
|
||||
/** roundTripTest() :
|
||||
* Compresses `srcBuff` into `compressedBuff`,
|
||||
* then decompresses `compressedBuff` into `resultBuff`.
|
||||
@@ -76,38 +54,6 @@ static size_t roundTripTest(void* resultBuff, size_t resultBuffCapacity,
|
||||
return ZSTD_decompress(resultBuff, resultBuffCapacity, compressedBuff, cSize);
|
||||
}
|
||||
|
||||
/** cctxParamRoundTripTest() :
|
||||
* Same as roundTripTest() except allows experimenting with ZSTD_CCtx_params. */
|
||||
static size_t cctxParamRoundTripTest(void* resultBuff, size_t resultBuffCapacity,
|
||||
void* compressedBuff, size_t compressedBuffCapacity,
|
||||
const void* srcBuff, size_t srcBuffSize)
|
||||
{
|
||||
ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||
ZSTD_CCtx_params* const cctxParams = ZSTD_createCCtxParams();
|
||||
ZSTD_inBuffer inBuffer = { srcBuff, srcBuffSize, 0 };
|
||||
ZSTD_outBuffer outBuffer = {compressedBuff, compressedBuffCapacity, 0 };
|
||||
|
||||
static const int maxClevel = 19;
|
||||
size_t const hashLength = MIN(128, srcBuffSize);
|
||||
unsigned const h32 = XXH32(srcBuff, hashLength, 0);
|
||||
int const cLevel = h32 % maxClevel;
|
||||
|
||||
/* Set parameters */
|
||||
CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_compressionLevel, cLevel) );
|
||||
CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_nbThreads, 2) );
|
||||
CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_overlapSizeLog, 5) );
|
||||
|
||||
|
||||
/* Apply parameters */
|
||||
CHECK_Z( ZSTD_CCtx_setParametersUsingCCtxParams(cctx, cctxParams) );
|
||||
|
||||
CHECK_Z (ZSTD_compress_generic(cctx, &outBuffer, &inBuffer, ZSTD_e_end) );
|
||||
|
||||
ZSTD_freeCCtxParams(cctxParams);
|
||||
ZSTD_freeCCtx(cctx);
|
||||
|
||||
return ZSTD_decompress(resultBuff, resultBuffCapacity, compressedBuff, outBuffer.pos);
|
||||
}
|
||||
|
||||
static size_t checkBuffers(const void* buff1, const void* buff2, size_t buffSize)
|
||||
{
|
||||
@@ -122,7 +68,16 @@ static size_t checkBuffers(const void* buff1, const void* buff2, size_t buffSize
|
||||
return pos;
|
||||
}
|
||||
|
||||
static void roundTripCheck(const void* srcBuff, size_t srcBuffSize, int testCCtxParams)
|
||||
static void crash(int errorCode){
|
||||
/* abort if AFL/libfuzzer, exit otherwise */
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* could also use __AFL_COMPILER */
|
||||
abort();
|
||||
#else
|
||||
exit(errorCode);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void roundTripCheck(const void* srcBuff, size_t srcBuffSize)
|
||||
{
|
||||
size_t const cBuffSize = ZSTD_compressBound(srcBuffSize);
|
||||
void* cBuff = malloc(cBuffSize);
|
||||
@@ -133,9 +88,7 @@ static void roundTripCheck(const void* srcBuff, size_t srcBuffSize, int testCCtx
|
||||
exit (1);
|
||||
}
|
||||
|
||||
{ size_t const result = testCCtxParams ?
|
||||
cctxParamRoundTripTest(rBuff, cBuffSize, cBuff, cBuffSize, srcBuff, srcBuffSize)
|
||||
: roundTripTest(rBuff, cBuffSize, cBuff, cBuffSize, srcBuff, srcBuffSize);
|
||||
{ size_t const result = roundTripTest(rBuff, cBuffSize, cBuff, cBuffSize, srcBuff, srcBuffSize);
|
||||
if (ZSTD_isError(result)) {
|
||||
fprintf(stderr, "roundTripTest error : %s \n", ZSTD_getErrorName(result));
|
||||
crash(1);
|
||||
@@ -209,7 +162,7 @@ static void loadFile(void* buffer, const char* fileName, size_t fileSize)
|
||||
}
|
||||
|
||||
|
||||
static void fileCheck(const char* fileName, int testCCtxParams)
|
||||
static void fileCheck(const char* fileName)
|
||||
{
|
||||
size_t const fileSize = getFileSize(fileName);
|
||||
void* buffer = malloc(fileSize);
|
||||
@@ -218,24 +171,16 @@ static void fileCheck(const char* fileName, int testCCtxParams)
|
||||
exit(4);
|
||||
}
|
||||
loadFile(buffer, fileName, fileSize);
|
||||
roundTripCheck(buffer, fileSize, testCCtxParams);
|
||||
roundTripCheck(buffer, fileSize);
|
||||
free (buffer);
|
||||
}
|
||||
|
||||
int main(int argCount, const char** argv) {
|
||||
int argNb = 1;
|
||||
int testCCtxParams = 0;
|
||||
if (argCount < 2) {
|
||||
fprintf(stderr, "Error : no argument : need input file \n");
|
||||
exit(9);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[argNb], "--cctxParams")) {
|
||||
testCCtxParams = 1;
|
||||
argNb++;
|
||||
}
|
||||
|
||||
fileCheck(argv[argNb], testCCtxParams);
|
||||
fileCheck(argv[1]);
|
||||
fprintf(stderr, "no pb detected\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#! /usr/bin/env python3
|
||||
|
||||
# ################################################################
|
||||
#
|
||||
# Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# ##########################################################################
|
||||
# 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.
|
||||
#
|
||||
|
||||
# Limitations:
|
||||
# - doesn't support filenames with spaces
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Test zstd interoperability between versions"""
|
||||
|
||||
# ################################################################
|
||||
#
|
||||
# Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under both the BSD-style license (found in the
|
||||
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# ################################################################
|
||||
# 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.
|
||||
#
|
||||
|
||||
import filecmp
|
||||
import glob
|
||||
|
||||
+1
-2
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2015-present, Yann Collet, Facebook, Inc.
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
+34
-110
@@ -5,7 +5,6 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -150,8 +149,6 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
U32 testNb = 1;
|
||||
ZSTD_CStream* zc = ZSTD_createCStream_advanced(customMem);
|
||||
ZSTD_DStream* zd = ZSTD_createDStream_advanced(customMem);
|
||||
ZSTDMT_CCtx* mtctx = ZSTDMT_createCCtx(2);
|
||||
|
||||
ZSTD_inBuffer inBuff, inBuff2;
|
||||
ZSTD_outBuffer outBuff;
|
||||
buffer_t dictionary = g_nullBuffer;
|
||||
@@ -200,9 +197,9 @@ 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)
|
||||
size_t const s = ZSTD_estimateCStreamSize_advanced(cParams)
|
||||
/* uses ZSTD_initCStream_usingDict() */
|
||||
+ ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
|
||||
+ ZSTD_estimateCDictSize_advanced(dictSize, cParams, 0);
|
||||
if (ZSTD_isError(s)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)s);
|
||||
}
|
||||
@@ -278,7 +275,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
DISPLAYLEVEL(5, " (windowSize : %u) ", (U32)fhi.windowSize);
|
||||
{ size_t const s = ZSTD_estimateDStreamSize(fhi.windowSize)
|
||||
/* uses ZSTD_initDStream_usingDict() */
|
||||
+ ZSTD_estimateDDictSize(dictSize, ZSTD_dlm_byCopy);
|
||||
+ ZSTD_estimateDDictSize(dictSize, 0);
|
||||
if (ZSTD_isError(s)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)s);
|
||||
} }
|
||||
@@ -480,7 +477,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_usingCDict_advanced with masked dictID : ", testNb++);
|
||||
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictionary.filled);
|
||||
ZSTD_frameParameters const fParams = { 1 /* contentSize */, 1 /* checksum */, 1 /* noDictID */};
|
||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dm_auto, cParams, customMem);
|
||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, 1 /* byReference */, ZSTD_dm_auto, cParams, customMem);
|
||||
size_t const initError = ZSTD_initCStream_usingCDict_advanced(zc, cdict, fParams, CNBufferSize);
|
||||
if (ZSTD_isError(initError)) goto _output_error;
|
||||
cSize = 0;
|
||||
@@ -608,25 +605,6 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != ZSTD_CONTENTSIZE_UNKNOWN) goto _output_error;
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
/* 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; }
|
||||
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; }
|
||||
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 */
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
|
||||
/* Overlen overwriting window data bug */
|
||||
DISPLAYLEVEL(3, "test%3i : wildcopy doesn't overwrite potential match data : ", testNb++);
|
||||
{ /* This test has a window size of 1024 bytes and consists of 3 blocks:
|
||||
@@ -665,7 +643,6 @@ _end:
|
||||
FUZ_freeDictionary(dictionary);
|
||||
ZSTD_freeCStream(zc);
|
||||
ZSTD_freeDStream(zd);
|
||||
ZSTDMT_freeCCtx(mtctx);
|
||||
free(CNBuffer);
|
||||
free(compressedBuffer);
|
||||
free(decodedBuffer);
|
||||
@@ -710,13 +687,6 @@ static size_t FUZ_randomLength(U32* seed, U32 maxLog)
|
||||
|
||||
#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
|
||||
|
||||
/* Return value in range minVal <= v <= maxVal */
|
||||
static U32 FUZ_randomClampedLength(U32* seed, U32 minVal, U32 maxVal)
|
||||
{
|
||||
U32 const mod = maxVal < minVal ? 1 : (maxVal + 1) - minVal;
|
||||
return (U32)((FUZ_rand(seed) % mod) + minVal);
|
||||
}
|
||||
|
||||
#define CHECK(cond, ...) { \
|
||||
if (cond) { \
|
||||
DISPLAY("Error => "); \
|
||||
@@ -916,16 +886,10 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres
|
||||
inBuff.size = inBuff.pos + readCSrcSize;
|
||||
outBuff.size = inBuff.pos + dstBuffSize;
|
||||
decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
||||
if (ZSTD_getErrorCode(decompressionResult) == ZSTD_error_checksum_wrong) {
|
||||
DISPLAY("checksum error : \n");
|
||||
findDiff(copyBuffer, dstBuffer, totalTestSize);
|
||||
}
|
||||
CHECK( ZSTD_isError(decompressionResult), "decompression error : %s",
|
||||
ZSTD_getErrorName(decompressionResult) );
|
||||
CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
|
||||
}
|
||||
CHECK (decompressionResult != 0, "frame not fully decoded");
|
||||
CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)",
|
||||
(U32)outBuff.pos, (U32)totalTestSize);
|
||||
CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size")
|
||||
CHECK (inBuff.pos != cSize, "compressed data should be fully read")
|
||||
{ U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
|
||||
if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
|
||||
@@ -1240,21 +1204,9 @@ _output_error:
|
||||
goto _cleanup;
|
||||
}
|
||||
|
||||
/** If useOpaqueAPI, sets param in cctxParams.
|
||||
* Otherwise, sets the param in zc. */
|
||||
static size_t setCCtxParameter(ZSTD_CCtx* zc, ZSTD_CCtx_params* cctxParams,
|
||||
ZSTD_cParameter param, unsigned value,
|
||||
U32 useOpaqueAPI)
|
||||
{
|
||||
if (useOpaqueAPI) {
|
||||
return ZSTD_CCtxParam_setParameter(cctxParams, param, value);
|
||||
} else {
|
||||
return ZSTD_CCtx_setParameter(zc, param, value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Tests for ZSTD_compress_generic() API */
|
||||
static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests, U32 const useOpaqueAPI)
|
||||
static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests)
|
||||
{
|
||||
U32 const maxSrcLog = bigTests ? 24 : 22;
|
||||
static const U32 maxSampleLog = 19;
|
||||
@@ -1278,7 +1230,6 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
U32 oldTestLog = 0;
|
||||
U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel() : g_cLevelMax_smallTests;
|
||||
U32 const nbThreadsMax = bigTests ? 5 : 1;
|
||||
ZSTD_CCtx_params* cctxParams = ZSTD_createCCtxParams();
|
||||
|
||||
/* allocations */
|
||||
cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
|
||||
@@ -1357,7 +1308,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
|
||||
if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1;
|
||||
{ int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1;
|
||||
CHECK_Z (setCCtxParameter(zc, cctxParams, ZSTD_p_compressionLevel, compressionLevel, useOpaqueAPI) );
|
||||
CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_compressionLevel, compressionLevel) );
|
||||
}
|
||||
} else {
|
||||
U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
|
||||
@@ -1387,66 +1338,41 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
cParams.targetLength = (U32)(cParams.targetLength * (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_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) );
|
||||
|
||||
/* mess with long distance matching parameters */
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_enableLongDistanceMatching, FUZ_rand(&lseed) & 63, useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashLog, FUZ_randomClampedLength(&lseed, ZSTD_HASHLOG_MIN, 23), useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmMinMatch, FUZ_randomClampedLength(&lseed, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX), useOpaqueAPI) );
|
||||
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) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_windowLog, cParams.windowLog) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_hashLog, cParams.hashLog) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_chainLog, cParams.chainLog) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_searchLog, cParams.searchLog) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_minMatch, cParams.searchLength) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_targetLength, cParams.targetLength) );
|
||||
|
||||
/* unconditionally set, to be sync with decoder */
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_refDictContent, FUZ_rand(&lseed) & 1) );
|
||||
if (FUZ_rand(&lseed) & 1) {
|
||||
CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) );
|
||||
if (dict && dictSize) {
|
||||
/* test that compression parameters are rejected (correctly) after loading a non-NULL dictionary */
|
||||
size_t const setError = ZSTD_CCtx_setParameter(zc, ZSTD_p_windowLog, cParams.windowLog-1) ;
|
||||
CHECK(!ZSTD_isError(setError), "ZSTD_CCtx_setParameter should have failed");
|
||||
} } else {
|
||||
CHECK_Z( ZSTD_CCtx_refPrefix(zc, dict, dictSize) );
|
||||
}
|
||||
|
||||
/* 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_setParameter(zc, ZSTD_p_checksumFlag, FUZ_rand(&lseed) & 1) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_dictIDFlag, FUZ_rand(&lseed) & 1) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_contentSizeFlag, FUZ_rand(&lseed) & 1) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
|
||||
DISPLAYLEVEL(5, "pledgedSrcSize : %u \n", (U32)pledgedSrcSize);
|
||||
|
||||
/* multi-threading parameters */
|
||||
{ U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1;
|
||||
U32 const nbThreads = MIN(nbThreadsCandidate, nbThreadsMax);
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_nbThreads, nbThreads, useOpaqueAPI) );
|
||||
CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_nbThreads, 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) );
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_jobSize, (U32)FUZ_rLogLength(&lseed, jobLog), useOpaqueAPI) );
|
||||
}
|
||||
}
|
||||
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z (setCCtxParameter(zc, cctxParams, ZSTD_p_forceMaxWindow, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
|
||||
|
||||
/* Apply parameters */
|
||||
if (useOpaqueAPI) {
|
||||
CHECK_Z (ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams) );
|
||||
}
|
||||
|
||||
if (FUZ_rand(&lseed) & 1) {
|
||||
if (FUZ_rand(&lseed) & 1) {
|
||||
CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) );
|
||||
} else {
|
||||
CHECK_Z( ZSTD_CCtx_loadDictionary_byReference(zc, dict, dictSize) );
|
||||
}
|
||||
if (dict && dictSize) {
|
||||
/* test that compression parameters are rejected (correctly) after loading a non-NULL dictionary */
|
||||
if (useOpaqueAPI) {
|
||||
size_t const setError = ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams);
|
||||
CHECK(!ZSTD_isError(setError), "ZSTD_CCtx_setParametersUsingCCtxParams should have failed");
|
||||
} else {
|
||||
size_t const setError = ZSTD_CCtx_setParameter(zc, ZSTD_p_windowLog, cParams.windowLog-1);
|
||||
CHECK(!ZSTD_isError(setError), "ZSTD_CCtx_setParameter should have failed");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CHECK_Z( ZSTD_CCtx_refPrefix(zc, dict, dictSize) );
|
||||
}
|
||||
} }
|
||||
CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_overlapSizeLog, FUZ_rand(&lseed) % 10) );
|
||||
CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_jobSize, (U32)FUZ_rLogLength(&lseed, jobLog)) );
|
||||
} } } }
|
||||
|
||||
/* multi-segments compression test */
|
||||
XXH64_reset(&xxhState, 0);
|
||||
@@ -1553,7 +1479,6 @@ _cleanup:
|
||||
ZSTD_freeCCtx(zc);
|
||||
ZSTD_freeDStream(zd);
|
||||
ZSTD_freeDStream(zd_noise);
|
||||
ZSTD_freeCCtxParams(cctxParams);
|
||||
free(cNoiseBuffer[0]);
|
||||
free(cNoiseBuffer[1]);
|
||||
free(cNoiseBuffer[2]);
|
||||
@@ -1569,6 +1494,7 @@ _output_error:
|
||||
goto _cleanup;
|
||||
}
|
||||
|
||||
|
||||
/*-*******************************************************
|
||||
* Command line
|
||||
*********************************************************/
|
||||
@@ -1604,7 +1530,6 @@ int main(int argc, const char** argv)
|
||||
e_api selected_api = simple_api;
|
||||
const char* const programName = argv[0];
|
||||
ZSTD_customMem const customNULL = ZSTD_defaultCMem;
|
||||
U32 useOpaqueAPI = 0;
|
||||
|
||||
/* Check command line */
|
||||
for(argNb=1; argNb<argc; argNb++) {
|
||||
@@ -1616,7 +1541,6 @@ int main(int argc, const char** argv)
|
||||
|
||||
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, "--no-big-tests")) { bigTests=0; continue; }
|
||||
|
||||
argument++;
|
||||
@@ -1730,7 +1654,7 @@ int main(int argc, const char** argv)
|
||||
result = fuzzerTests_MT(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
|
||||
break;
|
||||
case advanced_api :
|
||||
result = fuzzerTests_newAPI(seed, nbTests, testNb, ((double)proba) / 100, bigTests, useOpaqueAPI);
|
||||
result = fuzzerTests_newAPI(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
|
||||
break;
|
||||
default :
|
||||
assert(0); /* impossible */
|
||||
|
||||
@@ -34,7 +34,7 @@ EXT =
|
||||
endif
|
||||
|
||||
|
||||
all: fitblk example zwrapbench minigzip
|
||||
all: clean fitblk example zwrapbench minigzip
|
||||
|
||||
test: example fitblk example_zstd fitblk_zstd zwrapbench minigzip minigzip_zstd
|
||||
./example
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
@@ -36,6 +36,7 @@
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Constants
|
||||
**************************************/
|
||||
@@ -161,6 +162,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,
|
||||
ZSTD_CCtx* const ctx = ZSTD_createCCtx();
|
||||
ZSTD_DCtx* const dctx = ZSTD_createDCtx();
|
||||
U32 nbBlocks;
|
||||
UTIL_freq_t ticksPerSecond;
|
||||
|
||||
/* checks */
|
||||
if (!compressedBuffer || !resultBuffer || !blockTable || !ctx || !dctx)
|
||||
@@ -168,6 +170,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,
|
||||
|
||||
/* init */
|
||||
if (strlen(displayName)>17) displayName += strlen(displayName)-17; /* can only display 17 characters */
|
||||
UTIL_initTimer(&ticksPerSecond);
|
||||
|
||||
/* Init blockTable data */
|
||||
{ z_const char* srcPtr = (z_const char*)srcBuffer;
|
||||
@@ -207,17 +210,17 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,
|
||||
size_t cSize = 0;
|
||||
double ratio = 0.;
|
||||
|
||||
coolTime = UTIL_getTime();
|
||||
UTIL_getTime(&coolTime);
|
||||
DISPLAYLEVEL(2, "\r%79s\r", "");
|
||||
while (!cCompleted | !dCompleted) {
|
||||
UTIL_time_t clockStart;
|
||||
U64 clockLoop = g_nbIterations ? TIMELOOP_MICROSEC : 1;
|
||||
|
||||
/* overheat protection */
|
||||
if (UTIL_clockSpanMicro(coolTime) > ACTIVEPERIOD_MICROSEC) {
|
||||
if (UTIL_clockSpanMicro(coolTime, ticksPerSecond) > ACTIVEPERIOD_MICROSEC) {
|
||||
DISPLAYLEVEL(2, "\rcooling down ... \r");
|
||||
UTIL_sleep(COOLPERIOD_SEC);
|
||||
coolTime = UTIL_getTime();
|
||||
UTIL_getTime(&coolTime);
|
||||
}
|
||||
|
||||
/* Compression */
|
||||
@@ -225,15 +228,15 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,
|
||||
if (!cCompleted) memset(compressedBuffer, 0xE5, maxCompressedSize); /* warm up and erase result buffer */
|
||||
|
||||
UTIL_sleepMilli(1); /* give processor time to other processes */
|
||||
UTIL_waitForNextTick();
|
||||
clockStart = UTIL_getTime();
|
||||
UTIL_waitForNextTick(ticksPerSecond);
|
||||
UTIL_getTime(&clockStart);
|
||||
|
||||
if (!cCompleted) { /* still some time to do compression tests */
|
||||
U32 nbLoops = 0;
|
||||
if (compressor == BMK_ZSTD) {
|
||||
ZSTD_parameters const zparams = ZSTD_getParams(cLevel, avgSize, dictBufferSize);
|
||||
ZSTD_customMem const cmem = { NULL, NULL, NULL };
|
||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dm_auto, zparams.cParams, cmem);
|
||||
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, 1 /*byRef*/, ZSTD_dm_auto, zparams.cParams, cmem);
|
||||
if (cdict==NULL) EXM_THROW(1, "ZSTD_createCDict_advanced() allocation failure");
|
||||
|
||||
do {
|
||||
@@ -254,7 +257,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,
|
||||
blockTable[blockNb].cSize = rSize;
|
||||
}
|
||||
nbLoops++;
|
||||
} while (UTIL_clockSpanMicro(clockStart) < clockLoop);
|
||||
} while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop);
|
||||
ZSTD_freeCDict(cdict);
|
||||
} else if (compressor == BMK_ZSTD_STREAM) {
|
||||
ZSTD_parameters const zparams = ZSTD_getParams(cLevel, avgSize, dictBufferSize);
|
||||
@@ -283,7 +286,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,
|
||||
blockTable[blockNb].cSize = outBuffer.pos;
|
||||
}
|
||||
nbLoops++;
|
||||
} while (UTIL_clockSpanMicro(clockStart) < clockLoop);
|
||||
} while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop);
|
||||
ZSTD_freeCStream(zbc);
|
||||
} else if (compressor == BMK_ZWRAP_ZLIB_REUSE || compressor == BMK_ZWRAP_ZSTD_REUSE || compressor == BMK_ZLIB_REUSE) {
|
||||
z_stream def;
|
||||
@@ -324,7 +327,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,
|
||||
blockTable[blockNb].cSize = def.total_out;
|
||||
}
|
||||
nbLoops++;
|
||||
} while (UTIL_clockSpanMicro(clockStart) < clockLoop);
|
||||
} while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop);
|
||||
ret = deflateEnd(&def);
|
||||
if (ret != Z_OK) EXM_THROW(1, "deflateEnd failure");
|
||||
} else {
|
||||
@@ -357,9 +360,9 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,
|
||||
blockTable[blockNb].cSize = def.total_out;
|
||||
}
|
||||
nbLoops++;
|
||||
} while (UTIL_clockSpanMicro(clockStart) < clockLoop);
|
||||
} while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop);
|
||||
}
|
||||
{ U64 const clockSpan = UTIL_clockSpanMicro(clockStart);
|
||||
{ U64 const clockSpan = UTIL_clockSpanMicro(clockStart, ticksPerSecond);
|
||||
if (clockSpan < fastestC*nbLoops) fastestC = clockSpan / nbLoops;
|
||||
totalCTime += clockSpan;
|
||||
cCompleted = totalCTime>maxTime;
|
||||
@@ -379,8 +382,8 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,
|
||||
if (!dCompleted) memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */
|
||||
|
||||
UTIL_sleepMilli(1); /* give processor time to other processes */
|
||||
UTIL_waitForNextTick();
|
||||
clockStart = UTIL_getTime();
|
||||
UTIL_waitForNextTick(ticksPerSecond);
|
||||
UTIL_getTime(&clockStart);
|
||||
|
||||
if (!dCompleted) {
|
||||
U32 nbLoops = 0;
|
||||
@@ -403,7 +406,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,
|
||||
blockTable[blockNb].resSize = regenSize;
|
||||
}
|
||||
nbLoops++;
|
||||
} while (UTIL_clockSpanMicro(clockStart) < clockLoop);
|
||||
} while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop);
|
||||
ZSTD_freeDDict(ddict);
|
||||
} else if (compressor == BMK_ZSTD_STREAM) {
|
||||
ZSTD_inBuffer inBuffer;
|
||||
@@ -429,7 +432,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,
|
||||
blockTable[blockNb].resSize = outBuffer.pos;
|
||||
}
|
||||
nbLoops++;
|
||||
} while (UTIL_clockSpanMicro(clockStart) < clockLoop);
|
||||
} while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop);
|
||||
ZSTD_freeDStream(zbd);
|
||||
} else if (compressor == BMK_ZWRAP_ZLIB_REUSE || compressor == BMK_ZWRAP_ZSTD_REUSE || compressor == BMK_ZLIB_REUSE) {
|
||||
z_stream inf;
|
||||
@@ -465,7 +468,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,
|
||||
blockTable[blockNb].resSize = inf.total_out;
|
||||
}
|
||||
nbLoops++;
|
||||
} while (UTIL_clockSpanMicro(clockStart) < clockLoop);
|
||||
} while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop);
|
||||
ret = inflateEnd(&inf);
|
||||
if (ret != Z_OK) EXM_THROW(1, "inflateEnd failure");
|
||||
} else {
|
||||
@@ -499,9 +502,9 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,
|
||||
blockTable[blockNb].resSize = inf.total_out;
|
||||
}
|
||||
nbLoops++;
|
||||
} while (UTIL_clockSpanMicro(clockStart) < clockLoop);
|
||||
} while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop);
|
||||
}
|
||||
{ U64 const clockSpan = UTIL_clockSpanMicro(clockStart);
|
||||
{ U64 const clockSpan = UTIL_clockSpanMicro(clockStart, ticksPerSecond);
|
||||
if (clockSpan < fastestD*nbLoops) fastestD = clockSpan / nbLoops;
|
||||
totalDTime += clockSpan;
|
||||
dCompleted = totalDTime>maxTime;
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
|
||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
#ifndef ZSTD_ZLIBWRAPPER_H
|
||||
|
||||
Reference in New Issue
Block a user