Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fb5881303 | ||
|
|
7d3d5f2a20 | ||
|
|
23b55d6b3e | ||
|
|
bd21e4b264 | ||
|
|
8e20f133e7 | ||
|
|
16b353b207 | ||
|
|
bdf716bc64 | ||
|
|
a3296dae38 | ||
|
|
865ecf67ae | ||
|
|
78ebe4b5de | ||
|
|
c0ee26ec15 | ||
|
|
2fbc438a5d | ||
|
|
7276ab15bc | ||
|
|
5b9d6b992a | ||
|
|
461348c09a | ||
|
|
3b9df5896f | ||
|
|
978cea5d56 | ||
|
|
fedecb29d8 | ||
|
|
2598af451f | ||
|
|
9bfd371d9f | ||
|
|
2cdd33ae16 | ||
|
|
bc5fe33243 | ||
|
|
f014c3cd40 | ||
|
|
4307e870a2 | ||
|
|
a035654ab8 | ||
|
|
a2b6a8fbc6 | ||
|
|
3690fe30f3 | ||
|
|
82e7e2b47e | ||
|
|
37f36b9670 | ||
|
|
c6548eac8e | ||
|
|
b0ed66ef92 | ||
|
|
9a8ccd4ba3 | ||
|
|
7afd5d85d3 | ||
|
|
081691a3aa | ||
|
|
370933fa20 | ||
|
|
cce0edfdbe | ||
|
|
2312b819af | ||
|
|
78601d0806 | ||
|
|
34c0d85916 | ||
|
|
1047097dad | ||
|
|
38cdb6a072 | ||
|
|
4a9b7d136f | ||
|
|
74f65f624c | ||
|
|
8c115cbe23 | ||
|
|
2962fda93f | ||
|
|
405586d40a | ||
|
|
a4c8aa5e02 | ||
|
|
f03192c122 | ||
|
|
4d6e4a2978 | ||
|
|
c496fd261d | ||
|
|
de48f35306 | ||
|
|
b06710889f | ||
|
|
6653321ba3 | ||
|
|
4f59be7410 | ||
|
|
0fa9406ae2 | ||
|
|
c1913ed8c1 | ||
|
|
b6a9ded994 | ||
|
|
08981d2638 | ||
|
|
e8127b3f15 | ||
|
|
1c9b1ddac7 | ||
|
|
b1cce9a6ad | ||
|
|
4c144cf9c5 | ||
|
|
e2838d9eb9 | ||
|
|
4b201f98eb | ||
|
|
847349195f | ||
|
|
3a3da1712b | ||
|
|
448658a662 | ||
|
|
00ac0415ac | ||
|
|
eee59be6a8 | ||
|
|
b0f851675a | ||
|
|
151deaf143 | ||
|
|
12185ec5e7 | ||
|
|
0ce5f70ca8 | ||
|
|
e75db971fc | ||
|
|
53fe73a720 | ||
|
|
e7948fdf84 | ||
|
|
105b5839de | ||
|
|
6ac6472988 | ||
|
|
2af4e07326 | ||
|
|
7f248af036 | ||
|
|
11a392ce23 | ||
|
|
4ae5cb1ec9 | ||
|
|
b1a269437a | ||
|
|
c96151a25d | ||
|
|
f847909cf2 | ||
|
|
8a5f794e16 | ||
|
|
a49db88020 | ||
|
|
01b38ef162 | ||
|
|
bb3c9bf43a | ||
|
|
39a32f40c9 | ||
|
|
9eb2ccc9fb | ||
|
|
5aa5aa4df7 | ||
|
|
52a62e46f5 | ||
|
|
082755bd3f | ||
|
|
e20b601781 | ||
|
|
93cec0c1d6 | ||
|
|
3bb7992350 | ||
|
|
a49a4852c2 | ||
|
|
d9a1e37aec | ||
|
|
1aa6c7ccce | ||
|
|
27e2482217 | ||
|
|
afc2488973 | ||
|
|
7ed996f5a0 |
@@ -0,0 +1,184 @@
|
||||
name: generic-dev
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ dev, master, actionsTest ]
|
||||
|
||||
jobs:
|
||||
|
||||
# Dev PR jobs that still have to be migrated from travis
|
||||
#
|
||||
# icc (need self-hosted)
|
||||
# versionTag
|
||||
# valgrindTest (keeps failing for some reason. need investigation)
|
||||
# staticAnalyze (need trusty so need self-hosted)
|
||||
# pcc-fuzz: (need trusty so need self-hosted)
|
||||
# min-decomp-macros (flakey)
|
||||
#
|
||||
# setting up self-hosted is pretty straightforward, but
|
||||
# I need admins permissions to the repo for that it looks like
|
||||
# So I'm tabling that for now
|
||||
#
|
||||
# The master branch exclusive jobs will be in a separate
|
||||
# workflow file (the osx tests and meson build that is)
|
||||
|
||||
benchmarking:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: make benchmarking
|
||||
run: make benchmarking
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: make test
|
||||
run: make test
|
||||
|
||||
gcc-6-7-libzstd:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: gcc-6 + gcc-7 + libzstdmt compilation
|
||||
run: |
|
||||
make gcc6install gcc7install
|
||||
CC=gcc-6 CFLAGS=-Werror make -j all
|
||||
make clean
|
||||
CC=gcc-7 CFLAGS=-Werror make -j all
|
||||
make clean
|
||||
LDFLAGS=-Wl,--no-undefined make -C lib libzstd-mt
|
||||
make -C tests zbufftest-dll
|
||||
|
||||
gcc-8-asan-ubsan-testzstd:
|
||||
runs-on: ubuntu-16.04 # fails on 18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: gcc-8 + ASan + UBSan + Test Zstd
|
||||
run: |
|
||||
make gcc8install
|
||||
CC=gcc-8 CFLAGS="-Werror" make -j all
|
||||
make clean
|
||||
CC=gcc-8 make -j uasan-test-zstd </dev/null
|
||||
|
||||
gcc-6-asan-ubsan-testzstd-32bit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: gcc-6 + ASan + UBSan + Test Zstd, 32bit mode
|
||||
run: |
|
||||
make gcc6install libc6install
|
||||
CC=gcc-6 CFLAGS="-Werror -m32" make -j all32
|
||||
make clean
|
||||
CC=gcc-6 make -j uasan-test-zstd32
|
||||
|
||||
clang-38-msan-testzstd:
|
||||
runs-on: ubuntu-16.04 # fails on 18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: clang-3.8 + MSan + Test Zstd
|
||||
run: |
|
||||
# make clang38install (doesn't work)
|
||||
sudo apt-add-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.8 main"
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-3.8
|
||||
CC=clang-3.8 make clean msan-test-zstd HAVE_ZLIB=0 HAVE_LZ4=0 HAVE_LZMA=0
|
||||
|
||||
cmake-build-and-test-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: cmake build and test check
|
||||
run: make cmakebuild
|
||||
|
||||
gcc-8-asan-ubsan-fuzz:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: gcc-8 + ASan + UBSan + Fuzz Test
|
||||
run: |
|
||||
make gcc8install
|
||||
CC=gcc-8 make clean uasan-fuzztest
|
||||
|
||||
gcc-6-asan-ubsan-fuzz32:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: gcc-6 + ASan + UBSan + Fuzz Test 32bit
|
||||
run: |
|
||||
make gcc6install libc6install
|
||||
CC=gcc-6 CFLAGS="-O2 -m32" make uasan-fuzztest
|
||||
|
||||
clang-38-msan-fuzz:
|
||||
runs-on: ubuntu-16.04 # fails on 18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: clang-3.8 + MSan + Fuzz Test
|
||||
run: |
|
||||
# make clang38install (doesn't work)
|
||||
sudo apt-add-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.8 main"
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-3.8
|
||||
CC=clang-3.8 make clean msan-fuzztest
|
||||
|
||||
asan-ubsan-msan-regression:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: ASan + UBSan + MSan + Regression Test
|
||||
run: |
|
||||
make -j uasanregressiontest
|
||||
make clean
|
||||
make -j msanregressiontest
|
||||
|
||||
cpp-gnu90-c99-compatibility:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: C++, gnu90 and c99 compatibility
|
||||
run: |
|
||||
make cxxtest
|
||||
make clean
|
||||
make gnu90build
|
||||
make clean
|
||||
make c99build
|
||||
make clean
|
||||
make travis-install
|
||||
|
||||
mingw-cross-compilation:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: mingw cross-compilation
|
||||
run: |
|
||||
# sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix; (doesn't work)
|
||||
sudo apt-get install gcc-mingw-w64
|
||||
CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ CFLAGS="-Werror -O1" make zstd
|
||||
|
||||
armbuild:
|
||||
runs-on: ubuntu-16.04 # doesn't work on latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: ARM Build Test
|
||||
run: |
|
||||
make arminstall
|
||||
make armbuild
|
||||
|
||||
armfuzz:
|
||||
runs-on: ubuntu-16.04 # doesn't work on latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Qemu ARM emulation + Fuzz Test
|
||||
run: |
|
||||
make arminstall
|
||||
make armfuzz
|
||||
|
||||
bourne-shell:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Bourne shell compatibility (shellcheck)
|
||||
run: |
|
||||
wget https://github.com/koalaman/shellcheck/releases/download/v0.7.1/shellcheck-v0.7.1.linux.x86_64.tar.xz
|
||||
tar -xf shellcheck-v0.7.1.linux.x86_64.tar.xz
|
||||
shellcheck-v0.7.1/shellcheck --shell=sh --severity=warning --exclude=SC2010 tests/playTests.sh
|
||||
@@ -0,0 +1,68 @@
|
||||
name: generic-release
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
# This will eventually only be for pushes to master
|
||||
# but for dogfooding purposes, I'm running it even
|
||||
# on dev pushes
|
||||
branches: [ dev, master, actionsTest ]
|
||||
|
||||
jobs:
|
||||
# missing jobs
|
||||
#
|
||||
# ppc64le + fuzz test
|
||||
# Qemu PPC64 + Fuzz test
|
||||
# Qemu aarch64 + Fuzz Test (on Xenial)
|
||||
# versions comp
|
||||
# meson test
|
||||
|
||||
osx:
|
||||
runs-on: macos-10.15
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: OS-X
|
||||
run: |
|
||||
make test
|
||||
# make -c lib all (need to fix. not working right now)
|
||||
|
||||
zbuff:
|
||||
runs-on: ubuntu-16.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: zbuff test
|
||||
run: |
|
||||
make -C tests test-zbuff
|
||||
|
||||
tsan:
|
||||
runs-on: ubuntu-16.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: thread sanitizer
|
||||
run: |
|
||||
sudo apt-add-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.8 main"
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-3.8
|
||||
CC=clang-3.8 make tsan-test-zstream
|
||||
CC=clang-3.8 make tsan-fuzztest
|
||||
zlib-wrapper:
|
||||
runs-on: ubuntu-16.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: zlib wrapper test
|
||||
run: |
|
||||
make gpp6install valgrindinstall
|
||||
make -C zlibWrapper test
|
||||
make -C zlibWrapper valgrindTest
|
||||
|
||||
lz4-threadpool-partial-libs:
|
||||
runs-on: ubuntu-16.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: LZ4, thread pool, and partial libs testslib wrapper test
|
||||
run: |
|
||||
make lz4install
|
||||
make -C tests test-lz4
|
||||
make clean
|
||||
make -C tests test-pool
|
||||
make clean
|
||||
bash tests/libzstd_partial_builds.sh
|
||||
@@ -3,21 +3,28 @@ on: [pull_request]
|
||||
jobs:
|
||||
Fuzzing:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
sanitizer: [address, undefined, memory]
|
||||
steps:
|
||||
- name: Build Fuzzers
|
||||
- name: Build Fuzzers (${{ matrix.sanitizer }})
|
||||
id: build
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'zstd'
|
||||
dry-run: false
|
||||
- name: Run Fuzzers
|
||||
sanitizer: ${{ matrix.sanitizer }}
|
||||
- name: Run Fuzzers (${{ matrix.sanitizer }})
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'zstd'
|
||||
fuzz-seconds: 600
|
||||
dry-run: false
|
||||
sanitizer: ${{ matrix.sanitizer }}
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@v1
|
||||
if: failure()
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
with:
|
||||
name: artifacts
|
||||
name: ${{ matrix.sanitizer }}-artifacts
|
||||
path: ./out/artifacts
|
||||
|
||||
@@ -22,6 +22,7 @@ zstdmt
|
||||
|
||||
# Test artefacts
|
||||
tmp*
|
||||
*.zst
|
||||
dictionary.
|
||||
dictionary
|
||||
NUL
|
||||
@@ -32,6 +33,7 @@ bin/
|
||||
.buckd/
|
||||
buck-out/
|
||||
build-*
|
||||
*.gcda
|
||||
|
||||
# Other files
|
||||
.directory
|
||||
|
||||
@@ -126,6 +126,20 @@ just `contrib/largeNbDicts` and nothing else, you can run:
|
||||
scan-build make -C contrib/largeNbDicts largeNbDicts
|
||||
```
|
||||
|
||||
### Pitfalls of static analysis
|
||||
`scan-build` is part of our regular CI suite. Other static analyzers are not.
|
||||
|
||||
It can be useful to look at additional static analyzers once in a while (and we do), but it's not a good idea to multiply the nb of analyzers run continuously at each commit and PR. The reasons are :
|
||||
|
||||
- Static analyzers are full of false positive. The signal to noise ratio is actually pretty low.
|
||||
- A good CI policy is "zero-warning tolerance". That means that all issues must be solved, including false positives. This quickly becomes a tedious workload.
|
||||
- Multiple static analyzers will feature multiple kind of false positives, sometimes applying to the same code but in different ways leading to :
|
||||
+ torteous code, trying to please multiple constraints, hurting readability and therefore maintenance. Sometimes, such complexity introduce other more subtle bugs, that are just out of scope of the analyzers.
|
||||
+ sometimes, these constraints are mutually exclusive : if one try to solve one, the other static analyzer will complain, they can't be both happy at the same time.
|
||||
- As if that was not enough, the list of false positives change with each version. It's hard enough to follow one static analyzer, but multiple ones with their own update agenda, this quickly becomes a massive velocity reducer.
|
||||
|
||||
This is different from running a static analyzer once in a while, looking at the output, and __cherry picking__ a few warnings that seem helpful, either because they detected a genuine risk of bug, or because it helps expressing the code in a way which is more readable or more difficult to misuse. These kind of reports can be useful, and are accepted.
|
||||
|
||||
## Performance
|
||||
Performance is extremely important for zstd and we only merge pull requests whose performance
|
||||
landscape and corresponding trade-offs have been adequately analyzed, reproduced, and presented.
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
# You may select, at your option, one of the above-listed licenses.
|
||||
# ################################################################
|
||||
|
||||
# verbose mode (print commands) on V=1 or VERBOSE=1
|
||||
Q = $(if $(filter 1,$(V) $(VERBOSE)),,@)
|
||||
|
||||
PRGDIR = programs
|
||||
ZSTDDIR = lib
|
||||
BUILDIR = build
|
||||
@@ -46,8 +49,8 @@ allmost: allzstd zlibwrapper
|
||||
# skip zwrapper, can't build that on alternate architectures without the proper zlib installed
|
||||
.PHONY: allzstd
|
||||
allzstd: lib-all
|
||||
$(MAKE) -C $(PRGDIR) all
|
||||
$(MAKE) -C $(TESTDIR) all
|
||||
$(Q)$(MAKE) -C $(PRGDIR) all
|
||||
$(Q)$(MAKE) -C $(TESTDIR) all
|
||||
|
||||
.PHONY: all32
|
||||
all32:
|
||||
@@ -55,18 +58,19 @@ all32:
|
||||
$(MAKE) -C $(TESTDIR) all32
|
||||
|
||||
.PHONY: lib lib-release libzstd.a
|
||||
lib-all : lib
|
||||
lib lib-release lib-all :
|
||||
@$(MAKE) -C $(ZSTDDIR) $@
|
||||
$(Q)$(MAKE) -C $(ZSTDDIR) $@
|
||||
|
||||
.PHONY: zstd zstd-release
|
||||
zstd zstd-release:
|
||||
@$(MAKE) -C $(PRGDIR) $@
|
||||
cp $(PRGDIR)/zstd$(EXT) .
|
||||
$(Q)$(MAKE) -C $(PRGDIR) $@
|
||||
$(Q)cp $(PRGDIR)/zstd$(EXT) .
|
||||
|
||||
.PHONY: zstdmt
|
||||
zstdmt:
|
||||
@$(MAKE) -C $(PRGDIR) $@
|
||||
cp $(PRGDIR)/zstd$(EXT) ./zstdmt$(EXT)
|
||||
$(Q)$(MAKE) -C $(PRGDIR) $@
|
||||
$(Q)cp $(PRGDIR)/zstd$(EXT) ./zstdmt$(EXT)
|
||||
|
||||
.PHONY: zlibwrapper
|
||||
zlibwrapper: lib
|
||||
@@ -79,12 +83,12 @@ test: MOREFLAGS += -g -DDEBUGLEVEL=$(DEBUGLEVEL) -Werror
|
||||
test:
|
||||
MOREFLAGS="$(MOREFLAGS)" $(MAKE) -j -C $(PRGDIR) allVariants
|
||||
$(MAKE) -C $(TESTDIR) $@
|
||||
ZSTD=../../programs/zstd $(MAKE) -C doc/educational_decoder test
|
||||
ZSTD=../../programs/zstd $(MAKE) -C doc/educational_decoder $@
|
||||
|
||||
## shortest: same as `make check`
|
||||
.PHONY: shortest
|
||||
shortest:
|
||||
$(MAKE) -C $(TESTDIR) $@
|
||||
$(Q)$(MAKE) -C $(TESTDIR) $@
|
||||
|
||||
## check: run basic tests for `zstd` cli
|
||||
.PHONY: check
|
||||
@@ -127,17 +131,17 @@ cleanTabs:
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@$(MAKE) -C $(ZSTDDIR) $@ > $(VOID)
|
||||
@$(MAKE) -C $(PRGDIR) $@ > $(VOID)
|
||||
@$(MAKE) -C $(TESTDIR) $@ > $(VOID)
|
||||
@$(MAKE) -C $(ZWRAPDIR) $@ > $(VOID)
|
||||
@$(MAKE) -C examples/ $@ > $(VOID)
|
||||
@$(MAKE) -C contrib/gen_html $@ > $(VOID)
|
||||
@$(MAKE) -C contrib/pzstd $@ > $(VOID)
|
||||
@$(MAKE) -C contrib/seekable_format/examples $@ > $(VOID)
|
||||
@$(MAKE) -C contrib/largeNbDicts $@ > $(VOID)
|
||||
@$(RM) zstd$(EXT) zstdmt$(EXT) tmp*
|
||||
@$(RM) -r lz4
|
||||
$(Q)$(MAKE) -C $(ZSTDDIR) $@ > $(VOID)
|
||||
$(Q)$(MAKE) -C $(PRGDIR) $@ > $(VOID)
|
||||
$(Q)$(MAKE) -C $(TESTDIR) $@ > $(VOID)
|
||||
$(Q)$(MAKE) -C $(ZWRAPDIR) $@ > $(VOID)
|
||||
$(Q)$(MAKE) -C examples/ $@ > $(VOID)
|
||||
$(Q)$(MAKE) -C contrib/gen_html $@ > $(VOID)
|
||||
$(Q)$(MAKE) -C contrib/pzstd $@ > $(VOID)
|
||||
$(Q)$(MAKE) -C contrib/seekable_format/examples $@ > $(VOID)
|
||||
$(Q)$(MAKE) -C contrib/largeNbDicts $@ > $(VOID)
|
||||
$(Q)$(RM) zstd$(EXT) zstdmt$(EXT) tmp*
|
||||
$(Q)$(RM) -r lz4
|
||||
@echo Cleaning completed
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
@@ -161,7 +165,7 @@ EGREP = egrep $(EGREP_OPTIONS)
|
||||
## list: Print all targets and their descriptions (if provided)
|
||||
.PHONY: list
|
||||
list:
|
||||
@TARGETS=$$($(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null \
|
||||
$(Q)TARGETS=$$($(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null \
|
||||
| awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' \
|
||||
| $(EGREP) -v -e '^[^[:alnum:]]' | sort); \
|
||||
{ \
|
||||
@@ -176,13 +180,13 @@ list:
|
||||
|
||||
.PHONY: install armtest usan asan uasan
|
||||
install:
|
||||
@$(MAKE) -C $(ZSTDDIR) $@
|
||||
@$(MAKE) -C $(PRGDIR) $@
|
||||
$(Q)$(MAKE) -C $(ZSTDDIR) $@
|
||||
$(Q)$(MAKE) -C $(PRGDIR) $@
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall:
|
||||
@$(MAKE) -C $(ZSTDDIR) $@
|
||||
@$(MAKE) -C $(PRGDIR) $@
|
||||
$(Q)$(MAKE) -C $(ZSTDDIR) $@
|
||||
$(Q)$(MAKE) -C $(PRGDIR) $@
|
||||
|
||||
.PHONY: travis-install
|
||||
travis-install:
|
||||
|
||||
@@ -176,6 +176,12 @@ Going into `build` directory, you will find additional possibilities:
|
||||
You can build the zstd binary via buck by executing: `buck build programs:zstd` from the root of the repo.
|
||||
The output binary will be in `buck-out/gen/programs/`.
|
||||
|
||||
## Testing
|
||||
|
||||
You can run quick local smoke tests by executing the `playTest.sh` script from the `src/tests` directory.
|
||||
Two env variables `$ZSTD_BIN` and `$DATAGEN_BIN` are needed for the test script to locate the zstd and datagen binary.
|
||||
For information on CI testing, please refer to TESTING.md
|
||||
|
||||
## Status
|
||||
|
||||
Zstandard is currently deployed within Facebook. It is used continuously to compress large amounts of data in multiple formats and use cases.
|
||||
|
||||
@@ -60,7 +60,6 @@ macro(ADD_ZSTD_COMPILATION_FLAGS)
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
if( ${flag_var} )
|
||||
separate_arguments(${flag_var})
|
||||
list(REMOVE_DUPLICATES ${flag_var})
|
||||
string(REPLACE ";" " " ${flag_var} "${${flag_var}}")
|
||||
endif()
|
||||
endforeach ()
|
||||
|
||||
@@ -134,7 +134,7 @@ if (ZSTD_BUILD_STATIC)
|
||||
OUTPUT_NAME ${STATIC_LIBRARY_BASE_NAME})
|
||||
endif ()
|
||||
|
||||
if (UNIX)
|
||||
if (UNIX OR MINGW)
|
||||
# pkg-config
|
||||
set(PREFIX "${CMAKE_INSTALL_PREFIX}")
|
||||
set(LIBDIR "${CMAKE_INSTALL_LIBDIR}")
|
||||
@@ -152,9 +152,7 @@ endif ()
|
||||
# install target
|
||||
install(FILES
|
||||
"${LIBRARY_DIR}/zstd.h"
|
||||
"${LIBRARY_DIR}/deprecated/zbuff.h"
|
||||
"${LIBRARY_DIR}/dictBuilder/zdict.h"
|
||||
"${LIBRARY_DIR}/dictBuilder/cover.h"
|
||||
"${LIBRARY_DIR}/common/zstd_errors.h"
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
|
||||
@@ -163,6 +161,7 @@ install(TARGETS ${library_targets}
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
)
|
||||
|
||||
# uninstall target
|
||||
|
||||
@@ -127,6 +127,5 @@ pkgconfig.generate(libzstd,
|
||||
url: 'http://www.zstd.net/')
|
||||
|
||||
install_headers(join_paths(zstd_rootdir, 'lib/zstd.h'),
|
||||
join_paths(zstd_rootdir, 'lib/deprecated/zbuff.h'),
|
||||
join_paths(zstd_rootdir, 'lib/dictBuilder/zdict.h'),
|
||||
join_paths(zstd_rootdir, 'lib/common/zstd_errors.h'))
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
|
||||
namespace pzstd {
|
||||
|
||||
constexpr int ERROR = 1;
|
||||
constexpr int INFO = 2;
|
||||
constexpr int DEBUG = 3;
|
||||
constexpr int VERBOSE = 4;
|
||||
constexpr int kLogError = 1;
|
||||
constexpr int kLogInfo = 2;
|
||||
constexpr int kLogDebug = 3;
|
||||
constexpr int kLogVerbose = 4;
|
||||
|
||||
class Logger {
|
||||
std::mutex mutex_;
|
||||
|
||||
+11
-11
@@ -94,12 +94,12 @@ static std::uint64_t handleOneInput(const Options &options,
|
||||
if (!options.decompress) {
|
||||
double ratio = static_cast<double>(bytesWritten) /
|
||||
static_cast<double>(bytesRead + !bytesRead);
|
||||
state.log(INFO, "%-20s :%6.2f%% (%6" PRIu64 " => %6" PRIu64
|
||||
state.log(kLogInfo, "%-20s :%6.2f%% (%6" PRIu64 " => %6" PRIu64
|
||||
" bytes, %s)\n",
|
||||
inputFileName.c_str(), ratio * 100, bytesRead, bytesWritten,
|
||||
outputFileName.c_str());
|
||||
} else {
|
||||
state.log(INFO, "%-20s: %" PRIu64 " bytes \n",
|
||||
state.log(kLogInfo, "%-20s: %" PRIu64 " bytes \n",
|
||||
inputFileName.c_str(),bytesWritten);
|
||||
}
|
||||
}
|
||||
@@ -139,12 +139,12 @@ static FILE *openOutputFile(const Options &options,
|
||||
auto outputFd = std::fopen(outputFile.c_str(), "rb");
|
||||
if (outputFd != nullptr) {
|
||||
std::fclose(outputFd);
|
||||
if (!state.log.logsAt(INFO)) {
|
||||
if (!state.log.logsAt(kLogInfo)) {
|
||||
state.errorHolder.setError("Output file exists");
|
||||
return nullptr;
|
||||
}
|
||||
state.log(
|
||||
INFO,
|
||||
kLogInfo,
|
||||
"pzstd: %s already exists; do you wish to overwrite (y/n) ? ",
|
||||
outputFile.c_str());
|
||||
int c = getchar();
|
||||
@@ -170,7 +170,7 @@ int pzstdMain(const Options &options) {
|
||||
auto printErrorGuard = makeScopeGuard([&] {
|
||||
if (state.errorHolder.hasError()) {
|
||||
returnCode = 1;
|
||||
state.log(ERROR, "pzstd: %s: %s.\n", input.c_str(),
|
||||
state.log(kLogError, "pzstd: %s: %s.\n", input.c_str(),
|
||||
state.errorHolder.getError().c_str());
|
||||
}
|
||||
});
|
||||
@@ -388,7 +388,7 @@ std::uint64_t asyncCompressChunks(
|
||||
// Break the input up into chunks of size `step` and compress each chunk
|
||||
// independently.
|
||||
size_t step = calculateStep(size, numThreads, params);
|
||||
state.log(DEBUG, "Chosen frame size: %zu\n", step);
|
||||
state.log(kLogDebug, "Chosen frame size: %zu\n", step);
|
||||
auto status = FileStatus::Continue;
|
||||
while (status == FileStatus::Continue && !state.errorHolder.hasError()) {
|
||||
// Make a new input queue that we will put the chunk's input data into.
|
||||
@@ -403,7 +403,7 @@ std::uint64_t asyncCompressChunks(
|
||||
});
|
||||
// Pass the output queue to the writer thread.
|
||||
chunks.push(std::move(out));
|
||||
state.log(VERBOSE, "%s\n", "Starting a new frame");
|
||||
state.log(kLogVerbose, "%s\n", "Starting a new frame");
|
||||
// Fill the input queue for the compression job we just started
|
||||
status = readData(*in, ZSTD_CStreamInSize(), step, fd, &bytesRead);
|
||||
}
|
||||
@@ -540,14 +540,14 @@ std::uint64_t asyncDecompressFrames(
|
||||
if (frameSize == 0) {
|
||||
// We hit a non SkippableFrame ==> not compressed by pzstd or corrupted
|
||||
// Pass the rest of the source to this decompression task
|
||||
state.log(VERBOSE, "%s\n",
|
||||
state.log(kLogVerbose, "%s\n",
|
||||
"Input not in pzstd format, falling back to serial decompression");
|
||||
while (status == FileStatus::Continue && !state.errorHolder.hasError()) {
|
||||
status = readData(*in, chunkSize, chunkSize, fd, &totalBytesRead);
|
||||
}
|
||||
break;
|
||||
}
|
||||
state.log(VERBOSE, "Decompressing a frame of size %zu", frameSize);
|
||||
state.log(kLogVerbose, "Decompressing a frame of size %zu", frameSize);
|
||||
// Fill the input queue for the decompression job we just started
|
||||
status = readData(*in, chunkSize, frameSize, fd, &totalBytesRead);
|
||||
}
|
||||
@@ -573,7 +573,7 @@ std::uint64_t writeFile(
|
||||
bool decompress) {
|
||||
auto& errorHolder = state.errorHolder;
|
||||
auto lineClearGuard = makeScopeGuard([&state] {
|
||||
state.log.clear(INFO);
|
||||
state.log.clear(kLogInfo);
|
||||
});
|
||||
std::uint64_t bytesWritten = 0;
|
||||
std::shared_ptr<BufferWorkQueue> out;
|
||||
@@ -602,7 +602,7 @@ std::uint64_t writeFile(
|
||||
return bytesWritten;
|
||||
}
|
||||
bytesWritten += buffer.size();
|
||||
state.log.update(INFO, "Written: %u MB ",
|
||||
state.log.update(kLogInfo, "Written: %u MB ",
|
||||
static_cast<std::uint32_t>(bytesWritten >> 20));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class SharedState {
|
||||
auto parameters = options.determineParameters();
|
||||
cStreamPool.reset(new ResourcePool<ZSTD_CStream>{
|
||||
[this, parameters]() -> ZSTD_CStream* {
|
||||
this->log(VERBOSE, "%s\n", "Creating new ZSTD_CStream");
|
||||
this->log(kLogVerbose, "%s\n", "Creating new ZSTD_CStream");
|
||||
auto zcs = ZSTD_createCStream();
|
||||
if (zcs) {
|
||||
auto err = ZSTD_initCStream_advanced(
|
||||
@@ -59,7 +59,7 @@ class SharedState {
|
||||
} else {
|
||||
dStreamPool.reset(new ResourcePool<ZSTD_DStream>{
|
||||
[this]() -> ZSTD_DStream* {
|
||||
this->log(VERBOSE, "%s\n", "Creating new ZSTD_DStream");
|
||||
this->log(kLogVerbose, "%s\n", "Creating new ZSTD_DStream");
|
||||
auto zds = ZSTD_createDStream();
|
||||
if (zds) {
|
||||
auto err = ZSTD_initDStream(zds);
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
|
||||
# build artifacts
|
||||
zstddeclib.c
|
||||
zstdenclib.c
|
||||
zstd.c
|
||||
zstd.h
|
||||
|
||||
# test artifacts
|
||||
temp*
|
||||
|
||||
@@ -6,6 +6,56 @@ OUT_FILE="tempbin"
|
||||
# Optional temporary compiled WebAssembly
|
||||
OUT_WASM="temp.wasm"
|
||||
|
||||
# Source files to compile using Emscripten.
|
||||
IN_FILES="examples/emscripten.c"
|
||||
|
||||
# Emscripten build using emcc.
|
||||
emscripten_emcc_build() {
|
||||
# Compile the the same example as above
|
||||
CC_FLAGS="-Wall -Wextra -Werror -Os -g0 -flto"
|
||||
emcc $CC_FLAGS -s WASM=1 -I. -o $OUT_WASM $IN_FILES
|
||||
# Did compilation work?
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Compiling ${IN_FILES}: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
echo "Compiling ${IN_FILES}: PASSED"
|
||||
rm -f $OUT_WASM
|
||||
}
|
||||
|
||||
# Emscripten build using docker.
|
||||
emscripten_docker_build() {
|
||||
docker container run --rm \
|
||||
--volume $PWD:/code \
|
||||
--workdir /code \
|
||||
emscripten/emsdk:latest \
|
||||
emcc $CC_FLAGS -s WASM=1 -I. -o $OUT_WASM $IN_FILES
|
||||
# Did compilation work?
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Compiling ${IN_FILES} (using docker): FAILED"
|
||||
exit 1
|
||||
fi
|
||||
echo "Compiling ${IN_FILES} (using docker): PASSED"
|
||||
rm -f $OUT_WASM
|
||||
}
|
||||
|
||||
# Try Emscripten build using emcc or docker.
|
||||
try_emscripten_build() {
|
||||
which emcc > /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
emscripten_emcc_build
|
||||
return $?
|
||||
fi
|
||||
|
||||
which docker > /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
emscripten_docker_build
|
||||
return $?
|
||||
fi
|
||||
|
||||
echo "(Skipping Emscripten test)"
|
||||
}
|
||||
|
||||
# Amalgamate the sources
|
||||
./create_single_file_decoder.sh
|
||||
# Did combining work?
|
||||
@@ -35,21 +85,7 @@ if [ $retVal -ne 0 ]; then
|
||||
fi
|
||||
echo "Running simple.c: PASSED"
|
||||
|
||||
# Is Emscripten available?
|
||||
which emcc > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "(Skipping Emscripten test)"
|
||||
else
|
||||
# Compile the Emscripten example
|
||||
CC_FLAGS="-Wall -Wextra -Werror -Os -g0 -flto --llvm-lto 3 -lGL -DNDEBUG=1"
|
||||
emcc $CC_FLAGS -s WASM=1 -o $OUT_WASM examples/emscripten.c
|
||||
# Did compilation work?
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Compiling emscripten.c: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
echo "Compiling emscripten.c: PASSED"
|
||||
rm -f $OUT_WASM
|
||||
fi
|
||||
# Try Emscripten build if emcc or docker command is available.
|
||||
try_emscripten_build
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -9,6 +9,56 @@ OUT_FILE="tempbin"
|
||||
# Optional temporary compiled WebAssembly
|
||||
OUT_WASM="temp.wasm"
|
||||
|
||||
# Source files to compile using Emscripten.
|
||||
IN_FILES="zstd.c examples/roundtrip.c"
|
||||
|
||||
# Emscripten build using emcc.
|
||||
emscripten_emcc_build() {
|
||||
# Compile the the same example as above
|
||||
CC_FLAGS="-Wall -Wextra -Werror -Os -g0 -flto"
|
||||
emcc $CC_FLAGS -s WASM=1 -I. -o $OUT_WASM $IN_FILES
|
||||
# Did compilation work?
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Compiling ${IN_FILES}: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
echo "Compiling ${IN_FILES}: PASSED"
|
||||
rm -f $OUT_WASM
|
||||
}
|
||||
|
||||
# Emscripten build using docker.
|
||||
emscripten_docker_build() {
|
||||
docker container run --rm \
|
||||
--volume $PWD:/code \
|
||||
--workdir /code \
|
||||
emscripten/emsdk:latest \
|
||||
emcc $CC_FLAGS -s WASM=1 -I. -o $OUT_WASM $IN_FILES
|
||||
# Did compilation work?
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Compiling ${IN_FILES} (using docker): FAILED"
|
||||
exit 1
|
||||
fi
|
||||
echo "Compiling ${IN_FILES} (using docker): PASSED"
|
||||
rm -f $OUT_WASM
|
||||
}
|
||||
|
||||
# Try Emscripten build using emcc or docker.
|
||||
try_emscripten_build() {
|
||||
which emcc > /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
emscripten_emcc_build
|
||||
return $?
|
||||
fi
|
||||
|
||||
which docker > /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
emscripten_docker_build
|
||||
return $?
|
||||
fi
|
||||
|
||||
echo "(Skipping Emscripten test)"
|
||||
}
|
||||
|
||||
# Amalgamate the sources
|
||||
./create_single_file_library.sh
|
||||
# Did combining work?
|
||||
@@ -41,21 +91,7 @@ if [ $retVal -ne 0 ]; then
|
||||
fi
|
||||
echo "Running roundtrip.c: PASSED"
|
||||
|
||||
# Is Emscripten available?
|
||||
which emcc > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "(Skipping Emscripten test)"
|
||||
else
|
||||
# Compile the the same example as above
|
||||
CC_FLAGS="-Wall -Wextra -Werror -Os -g0 -flto"
|
||||
emcc $CC_FLAGS -s WASM=1 -I. -o $OUT_WASM zstd.c examples/roundtrip.c
|
||||
# Did compilation work?
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Compiling emscripten.c: FAILED"
|
||||
exit 1
|
||||
fi
|
||||
echo "Compiling emscripten.c: PASSED"
|
||||
rm -f $OUT_WASM
|
||||
fi
|
||||
# Try Emscripten build if emcc or docker command is available.
|
||||
try_emscripten_build
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -39,9 +39,6 @@
|
||||
#undef XXH_INLINE_ALL
|
||||
#define XXH_INLINE_ALL
|
||||
#define ZSTD_LEGACY_SUPPORT 0
|
||||
#define ZSTD_LIB_DICTBUILDER 0
|
||||
#define ZSTD_LIB_DEPRECATED 0
|
||||
#define ZSTD_NOBENCH
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#define ZSTD_MULTITHREAD
|
||||
#endif
|
||||
@@ -74,3 +71,8 @@
|
||||
#include "decompress/zstd_ddict.c"
|
||||
#include "decompress/zstd_decompress.c"
|
||||
#include "decompress/zstd_decompress_block.c"
|
||||
|
||||
#include "dictBuilder/cover.c"
|
||||
#include "dictBuilder/divsufsort.c"
|
||||
#include "dictBuilder/fastcover.c"
|
||||
#include "dictBuilder/zdict.c"
|
||||
|
||||
@@ -37,9 +37,6 @@
|
||||
#undef XXH_INLINE_ALL
|
||||
#define XXH_INLINE_ALL
|
||||
#define ZSTD_LEGACY_SUPPORT 0
|
||||
#define ZSTD_LIB_COMPRESSION 0
|
||||
#define ZSTD_LIB_DEPRECATED 0
|
||||
#define ZSTD_NOBENCH
|
||||
#define ZSTD_STRIP_ERROR_STRINGS
|
||||
|
||||
#include "common/debug.c"
|
||||
|
||||
@@ -3,7 +3,7 @@ Zstandard Compression Format
|
||||
|
||||
### Notices
|
||||
|
||||
Copyright (c) 2016-present Yann Collet, Facebook, Inc.
|
||||
Copyright (c) 2016-2020 Yann Collet, Facebook, Inc.
|
||||
|
||||
Permission is granted to copy and distribute this document
|
||||
for any purpose and without charge,
|
||||
@@ -16,7 +16,7 @@ Distribution of this document is unlimited.
|
||||
|
||||
### Version
|
||||
|
||||
0.3.5 (13/11/19)
|
||||
0.3.6 (25/05/20)
|
||||
|
||||
|
||||
Introduction
|
||||
@@ -291,21 +291,10 @@ Format is __little-endian__.
|
||||
It's allowed to represent a small ID (for example `13`)
|
||||
with a large 4-bytes dictionary ID, even if it is less efficient.
|
||||
|
||||
_Reserved ranges :_
|
||||
Within private environments, any `Dictionary_ID` can be used.
|
||||
|
||||
However, for frames and dictionaries distributed in public space,
|
||||
`Dictionary_ID` must be attributed carefully.
|
||||
Rules for public environment are not yet decided,
|
||||
but the following ranges are reserved for some future registrar :
|
||||
- low range : `<= 32767`
|
||||
- high range : `>= (1 << 31)`
|
||||
|
||||
Outside of these ranges, any value of `Dictionary_ID`
|
||||
which is both `>= 32768` and `< (1<<31)` can be used freely,
|
||||
even in public environment.
|
||||
|
||||
|
||||
A value of `0` has same meaning as no `Dictionary_ID`,
|
||||
in which case the frame may or may not need a dictionary to be decoded,
|
||||
and the ID of such a dictionary is not specified.
|
||||
The decoder must know this information by other means.
|
||||
|
||||
#### `Frame_Content_Size`
|
||||
|
||||
@@ -389,7 +378,7 @@ __`Block_Size`__
|
||||
The upper 21 bits of `Block_Header` represent the `Block_Size`.
|
||||
|
||||
When `Block_Type` is `Compressed_Block` or `Raw_Block`,
|
||||
`Block_Size` is the size of `Block_Content` (hence excluding `Block_Header`).
|
||||
`Block_Size` is the size of `Block_Content` (hence excluding `Block_Header`).
|
||||
|
||||
When `Block_Type` is `RLE_Block`, since `Block_Content`’s size is always 1,
|
||||
`Block_Size` represents the number of times this byte must be repeated.
|
||||
@@ -1429,13 +1418,17 @@ __`Dictionary_ID`__ : 4 bytes, stored in __little-endian__ format.
|
||||
It's used by decoders to check if they use the correct dictionary.
|
||||
|
||||
_Reserved ranges :_
|
||||
If the frame is going to be distributed in a private environment,
|
||||
any `Dictionary_ID` can be used.
|
||||
However, for public distribution of compressed frames,
|
||||
the following ranges are reserved and shall not be used :
|
||||
If the dictionary is going to be distributed in a public environment,
|
||||
the following ranges of `Dictionary_ID` are reserved for some future registrar
|
||||
and shall not be used :
|
||||
|
||||
- low range : <= 32767
|
||||
- high range : >= (2^31)
|
||||
|
||||
Outside of these ranges, any value of `Dictionary_ID`
|
||||
which is both `>= 32768` and `< (1<<31)` can be used freely,
|
||||
even in public environment.
|
||||
|
||||
- low range : <= 32767
|
||||
- high range : >= (2^31)
|
||||
|
||||
__`Entropy_Tables`__ : follow the same format as tables in [compressed blocks].
|
||||
See the relevant [FSE](#fse-table-description)
|
||||
@@ -1455,7 +1448,7 @@ __`Content`__ : The rest of the dictionary is its content.
|
||||
As long as the amount of data decoded from this frame is less than or
|
||||
equal to `Window_Size`, sequence commands may specify offsets longer
|
||||
than the total length of decoded output so far to reference back to the
|
||||
dictionary, even parts of the dictionary with offsets larger than `Window_Size`.
|
||||
dictionary, even parts of the dictionary with offsets larger than `Window_Size`.
|
||||
After the total output has surpassed `Window_Size` however,
|
||||
this is no longer allowed and the dictionary is no longer accessible.
|
||||
|
||||
@@ -1673,6 +1666,7 @@ or at least provide a meaningful error code explaining for which reason it canno
|
||||
|
||||
Version changes
|
||||
---------------
|
||||
- 0.3.6 : clarifications for Dictionary_ID
|
||||
- 0.3.5 : clarifications for Block_Maximum_Size
|
||||
- 0.3.4 : clarifications for FSE decoding table
|
||||
- 0.3.3 : clarifications for field Block_Size
|
||||
|
||||
@@ -39,6 +39,7 @@ static void compressFile_orDie(const char* fname, const char* outName, int cLeve
|
||||
*/
|
||||
CHECK_ZSTD( ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, cLevel) );
|
||||
CHECK_ZSTD( ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1) );
|
||||
ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, 4);
|
||||
|
||||
/* This loop read from the input file, compresses that entire chunk,
|
||||
* and writes all output produced to the output file.
|
||||
|
||||
+9
-9
@@ -49,6 +49,7 @@ ifeq ($HAVE_COLORNEVER, 1)
|
||||
GREP_OPTIONS += --color=never
|
||||
endif
|
||||
GREP = grep $(GREP_OPTIONS)
|
||||
SED_ERE_OPT ?= -E
|
||||
|
||||
ZSTDCOMMON_FILES := $(sort $(wildcard common/*.c))
|
||||
ZSTDCOMP_FILES := $(sort $(wildcard compress/*.c))
|
||||
@@ -220,13 +221,14 @@ libzstd : $(LIBZSTD)
|
||||
.PHONY: lib
|
||||
lib : libzstd.a libzstd
|
||||
|
||||
.PHONY: lib-mt
|
||||
# note : do not define lib-mt or lib-release as .PHONY
|
||||
# make does not consider implicit pattern rule for .PHONY target
|
||||
|
||||
%-mt : CPPFLAGS += -DZSTD_MULTITHREAD
|
||||
%-mt : LDFLAGS += -pthread
|
||||
%-mt : %
|
||||
@echo multi-threading build completed
|
||||
|
||||
.PHONY: lib-release
|
||||
%-release : DEBUGFLAGS :=
|
||||
%-release : %
|
||||
@echo release build completed
|
||||
@@ -268,13 +270,13 @@ LIBDIR ?= $(libdir)
|
||||
includedir ?= $(PREFIX)/include
|
||||
INCLUDEDIR ?= $(includedir)
|
||||
|
||||
PCLIBDIR ?= $(shell echo "$(LIBDIR)" | sed -n -E -e "s@^$(EXEC_PREFIX)(/|$$)@@p")
|
||||
PCINCDIR ?= $(shell echo "$(INCLUDEDIR)" | sed -n -E -e "s@^$(PREFIX)(/|$$)@@p")
|
||||
PCLIBDIR ?= $(shell echo "$(LIBDIR)" | sed -n $(SED_ERE_OPT) -e "s@^$(EXEC_PREFIX)(/|$$)@@p")
|
||||
PCINCDIR ?= $(shell echo "$(INCLUDEDIR)" | sed -n $(SED_ERE_OPT) -e "s@^$(PREFIX)(/|$$)@@p")
|
||||
|
||||
ifeq (,$(PCLIBDIR))
|
||||
# Additional prefix check is required, since the empty string is technically a
|
||||
# valid PCLIBDIR
|
||||
ifeq (,$(shell echo "$(LIBDIR)" | sed -n -E -e "\\@^$(EXEC_PREFIX)(/|$$)@ p"))
|
||||
ifeq (,$(shell echo "$(LIBDIR)" | sed -n $(SED_ERE_OPT) -e "\\@^$(EXEC_PREFIX)(/|$$)@ p"))
|
||||
$(error configured libdir ($(LIBDIR)) is outside of prefix ($(PREFIX)), can't generate pkg-config file)
|
||||
endif
|
||||
endif
|
||||
@@ -282,7 +284,7 @@ endif
|
||||
ifeq (,$(PCINCDIR))
|
||||
# Additional prefix check is required, since the empty string is technically a
|
||||
# valid PCINCDIR
|
||||
ifeq (,$(shell echo "$(INCLUDEDIR)" | sed -n -E -e "\\@^$(PREFIX)(/|$$)@ p"))
|
||||
ifeq (,$(shell echo "$(INCLUDEDIR)" | sed -n $(SED_ERE_OPT) -e "\\@^$(PREFIX)(/|$$)@ p"))
|
||||
$(error configured includedir ($(INCLUDEDIR)) is outside of exec_prefix ($(EXEC_PREFIX)), can't generate pkg-config file)
|
||||
endif
|
||||
endif
|
||||
@@ -306,7 +308,7 @@ INSTALL_DATA ?= $(INSTALL) -m 644
|
||||
libzstd.pc:
|
||||
libzstd.pc: libzstd.pc.in
|
||||
@echo creating pkgconfig
|
||||
$(Q)@sed -E -e 's|@PREFIX@|$(PREFIX)|' \
|
||||
$(Q)@sed $(SED_ERE_OPT) -e 's|@PREFIX@|$(PREFIX)|' \
|
||||
-e 's|@LIBDIR@|$(PCLIBDIR)|' \
|
||||
-e 's|@INCLUDEDIR@|$(PCINCDIR)|' \
|
||||
-e 's|@VERSION@|$(VERSION)|' \
|
||||
@@ -336,7 +338,6 @@ install-includes:
|
||||
$(Q)$(INSTALL) -d -m 755 $(DESTDIR)$(INCLUDEDIR)/
|
||||
$(Q)$(INSTALL_DATA) zstd.h $(DESTDIR)$(INCLUDEDIR)
|
||||
$(Q)$(INSTALL_DATA) common/zstd_errors.h $(DESTDIR)$(INCLUDEDIR)
|
||||
$(Q)$(INSTALL_DATA) deprecated/zbuff.h $(DESTDIR)$(INCLUDEDIR) # prototypes generate deprecation warnings
|
||||
$(Q)$(INSTALL_DATA) dictBuilder/zdict.h $(DESTDIR)$(INCLUDEDIR)
|
||||
|
||||
uninstall:
|
||||
@@ -347,7 +348,6 @@ uninstall:
|
||||
$(Q)$(RM) $(DESTDIR)$(PKGCONFIGDIR)/libzstd.pc
|
||||
$(Q)$(RM) $(DESTDIR)$(INCLUDEDIR)/zstd.h
|
||||
$(Q)$(RM) $(DESTDIR)$(INCLUDEDIR)/zstd_errors.h
|
||||
$(Q)$(RM) $(DESTDIR)$(INCLUDEDIR)/zbuff.h # Deprecated streaming functions
|
||||
$(Q)$(RM) $(DESTDIR)$(INCLUDEDIR)/zdict.h
|
||||
@echo zstd libraries successfully uninstalled
|
||||
|
||||
|
||||
@@ -38,6 +38,17 @@
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
On MSVC qsort requires that functions passed into it use the __cdecl calling conversion(CC).
|
||||
This explictly marks such functions as __cdecl so that the code will still compile
|
||||
if a CC other than __cdecl has been made the default.
|
||||
*/
|
||||
#if defined(_MSC_VER)
|
||||
# define WIN_CDECL __cdecl
|
||||
#else
|
||||
# define WIN_CDECL
|
||||
#endif
|
||||
|
||||
/**
|
||||
* FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant
|
||||
* parameters. They must be inlined for the compiler to eliminate the constant
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@ extern "C" {
|
||||
# include <assert.h>
|
||||
#else
|
||||
# ifndef assert /* assert may be already defined, due to prior #include <assert.h> */
|
||||
# define assert(condition) ((void)0) /* disable assert (default) */
|
||||
# define assert(condition) ((void) (condition)) /* disable assert (default) */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
+4
-4
@@ -301,7 +301,7 @@ int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque)
|
||||
struct POOL_ctx_s {
|
||||
int dummy;
|
||||
};
|
||||
static POOL_ctx g_ctx;
|
||||
static POOL_ctx g_poolCtx;
|
||||
|
||||
POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
|
||||
return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
|
||||
@@ -311,11 +311,11 @@ POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM
|
||||
(void)numThreads;
|
||||
(void)queueSize;
|
||||
(void)customMem;
|
||||
return &g_ctx;
|
||||
return &g_poolCtx;
|
||||
}
|
||||
|
||||
void POOL_free(POOL_ctx* ctx) {
|
||||
assert(!ctx || ctx == &g_ctx);
|
||||
assert(!ctx || ctx == &g_poolCtx);
|
||||
(void)ctx;
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) {
|
||||
|
||||
size_t POOL_sizeof(POOL_ctx* ctx) {
|
||||
if (ctx==NULL) return 0; /* supports sizeof NULL */
|
||||
assert(ctx == &g_ctx);
|
||||
assert(ctx == &g_poolCtx);
|
||||
return sizeof(*ctx);
|
||||
}
|
||||
|
||||
|
||||
+110
-104
@@ -1123,45 +1123,61 @@ ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
|
||||
return tableSpace + optSpace;
|
||||
}
|
||||
|
||||
static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal(
|
||||
const ZSTD_compressionParameters* cParams,
|
||||
const ldmParams_t* ldmParams,
|
||||
const int isStatic,
|
||||
const size_t buffInSize,
|
||||
const size_t buffOutSize,
|
||||
const U64 pledgedSrcSize)
|
||||
{
|
||||
size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << cParams->windowLog), pledgedSrcSize));
|
||||
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
|
||||
U32 const divider = (cParams->minMatch==3) ? 3 : 4;
|
||||
size_t const maxNbSeq = blockSize / divider;
|
||||
size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
|
||||
+ ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
|
||||
+ 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
|
||||
size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE);
|
||||
size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
|
||||
size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, /* forCCtx */ 1);
|
||||
|
||||
size_t const ldmSpace = ZSTD_ldm_getTableSize(*ldmParams);
|
||||
size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(*ldmParams, blockSize);
|
||||
size_t const ldmSeqSpace = ldmParams->enableLdm ?
|
||||
ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0;
|
||||
|
||||
|
||||
size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize)
|
||||
+ ZSTD_cwksp_alloc_size(buffOutSize);
|
||||
|
||||
size_t const cctxSpace = isStatic ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0;
|
||||
|
||||
size_t const neededSpace =
|
||||
cctxSpace +
|
||||
entropySpace +
|
||||
blockStateSpace +
|
||||
ldmSpace +
|
||||
ldmSeqSpace +
|
||||
matchStateSize +
|
||||
tokenSpace +
|
||||
bufferSpace;
|
||||
|
||||
DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace);
|
||||
return neededSpace;
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
||||
{
|
||||
RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
|
||||
{ ZSTD_compressionParameters const cParams =
|
||||
ZSTD_compressionParameters const cParams =
|
||||
ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0);
|
||||
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
|
||||
U32 const divider = (cParams.minMatch==3) ? 3 : 4;
|
||||
size_t const maxNbSeq = blockSize / divider;
|
||||
size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
|
||||
+ ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
|
||||
+ 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
|
||||
size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE);
|
||||
size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
|
||||
size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1);
|
||||
|
||||
size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams);
|
||||
size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq));
|
||||
|
||||
/* estimateCCtxSize is for one-shot compression. So no buffers should
|
||||
* be needed. However, we still allocate two 0-sized buffers, which can
|
||||
* take space under ASAN. */
|
||||
size_t const bufferSpace = ZSTD_cwksp_alloc_size(0)
|
||||
+ ZSTD_cwksp_alloc_size(0);
|
||||
|
||||
size_t const cctxSpace = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx));
|
||||
|
||||
size_t const neededSpace =
|
||||
cctxSpace +
|
||||
entropySpace +
|
||||
blockStateSpace +
|
||||
ldmSpace +
|
||||
ldmSeqSpace +
|
||||
matchStateSize +
|
||||
tokenSpace +
|
||||
bufferSpace;
|
||||
|
||||
DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace);
|
||||
return neededSpace;
|
||||
}
|
||||
RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
|
||||
/* estimateCCtxSize is for one-shot compression. So no buffers should
|
||||
* be needed. However, we still allocate two 0-sized buffers, which can
|
||||
* take space under ASAN. */
|
||||
return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
|
||||
&cParams, ¶ms->ldmParams, 1, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN);
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
|
||||
@@ -1192,14 +1208,13 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
||||
RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
|
||||
{ ZSTD_compressionParameters const cParams =
|
||||
ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0);
|
||||
size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
|
||||
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 = ZSTD_cwksp_alloc_size(inBuffSize)
|
||||
+ ZSTD_cwksp_alloc_size(outBuffSize);
|
||||
|
||||
return CCtxSize + streamingSize;
|
||||
return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
|
||||
&cParams, ¶ms->ldmParams, 1, inBuffSize, outBuffSize,
|
||||
ZSTD_CONTENTSIZE_UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1441,45 +1456,28 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
|
||||
U32 const divider = (params.cParams.minMatch==3) ? 3 : 4;
|
||||
size_t const maxNbSeq = blockSize / divider;
|
||||
size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
|
||||
+ ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
|
||||
+ 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
|
||||
size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
|
||||
size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0;
|
||||
size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1);
|
||||
size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize);
|
||||
|
||||
ZSTD_indexResetPolicy_e needsIndexReset = zc->initialized ? ZSTDirp_continue : ZSTDirp_reset;
|
||||
int const indexTooClose = ZSTD_indexTooCloseToMax(zc->blockState.matchState.window);
|
||||
ZSTD_indexResetPolicy_e needsIndexReset =
|
||||
(!indexTooClose && zc->initialized) ? ZSTDirp_continue : ZSTDirp_reset;
|
||||
|
||||
if (ZSTD_indexTooCloseToMax(zc->blockState.matchState.window)) {
|
||||
needsIndexReset = ZSTDirp_reset;
|
||||
}
|
||||
size_t const neededSpace =
|
||||
ZSTD_estimateCCtxSize_usingCCtxParams_internal(
|
||||
¶ms.cParams, ¶ms.ldmParams, zc->staticSize != 0,
|
||||
buffInSize, buffOutSize, pledgedSrcSize);
|
||||
FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!");
|
||||
|
||||
if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0);
|
||||
|
||||
/* Check if workspace is large enough, alloc a new one if needed */
|
||||
{ size_t const cctxSpace = zc->staticSize ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0;
|
||||
size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE);
|
||||
size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
|
||||
size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) + ZSTD_cwksp_alloc_size(buffOutSize);
|
||||
size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams);
|
||||
size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq));
|
||||
|
||||
size_t const neededSpace =
|
||||
cctxSpace +
|
||||
entropySpace +
|
||||
blockStateSpace +
|
||||
ldmSpace +
|
||||
ldmSeqSpace +
|
||||
matchStateSize +
|
||||
tokenSpace +
|
||||
bufferSpace;
|
||||
|
||||
{
|
||||
int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace;
|
||||
int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace);
|
||||
|
||||
DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers",
|
||||
neededSpace>>10, matchStateSize>>10, bufferSpace>>10);
|
||||
DEBUGLOG(4, "Need %zu B workspace", neededSpace);
|
||||
DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
|
||||
|
||||
if (workspaceTooSmall || workspaceWasteful) {
|
||||
@@ -1579,6 +1577,12 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
zc->ldmState.loadedDictEnd = 0;
|
||||
}
|
||||
|
||||
/* Due to alignment, when reusing a workspace, we can actually consume
|
||||
* up to 3 extra bytes for alignment. See the comments in zstd_cwksp.h
|
||||
*/
|
||||
assert(ZSTD_cwksp_used(ws) >= neededSpace &&
|
||||
ZSTD_cwksp_used(ws) <= neededSpace + 3);
|
||||
|
||||
DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws));
|
||||
zc->initialized = 1;
|
||||
|
||||
@@ -1638,7 +1642,7 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
|
||||
assert(windowLog != 0);
|
||||
/* Resize working context table params for input only, since the dict
|
||||
* has its own tables. */
|
||||
/* pledgeSrcSize == 0 means 0! */
|
||||
/* pledgedSrcSize == 0 means 0! */
|
||||
params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0);
|
||||
params.cParams.windowLog = windowLog;
|
||||
FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
|
||||
@@ -2887,22 +2891,28 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
|
||||
|
||||
|
||||
/* Dictionaries that assign zero probability to symbols that show up causes problems
|
||||
when FSE encoding. Refuse dictionaries that assign zero probability to symbols
|
||||
that we may encounter during compression.
|
||||
NOTE: This behavior is not standard and could be improved in the future. */
|
||||
static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
|
||||
* when FSE encoding. Mark dictionaries with zero probability symbols as FSE_repeat_check
|
||||
* and only dictionaries with 100% valid symbols can be assumed valid.
|
||||
*/
|
||||
static FSE_repeat ZSTD_dictNCountRepeat(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue)
|
||||
{
|
||||
U32 s;
|
||||
RETURN_ERROR_IF(dictMaxSymbolValue < maxSymbolValue, dictionary_corrupted, "dict fse tables don't have all symbols");
|
||||
for (s = 0; s <= maxSymbolValue; ++s) {
|
||||
RETURN_ERROR_IF(normalizedCounter[s] == 0, dictionary_corrupted, "dict fse tables don't have all symbols");
|
||||
if (dictMaxSymbolValue < maxSymbolValue) {
|
||||
return FSE_repeat_check;
|
||||
}
|
||||
return 0;
|
||||
for (s = 0; s <= maxSymbolValue; ++s) {
|
||||
if (normalizedCounter[s] == 0) {
|
||||
return FSE_repeat_check;
|
||||
}
|
||||
}
|
||||
return FSE_repeat_valid;
|
||||
}
|
||||
|
||||
size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
|
||||
short* offcodeNCount, unsigned* offcodeMaxValue,
|
||||
const void* const dict, size_t dictSize)
|
||||
{
|
||||
short offcodeNCount[MaxOff+1];
|
||||
unsigned offcodeMaxValue = MaxOff;
|
||||
const BYTE* dictPtr = (const BYTE*)dict; /* skip magic num and dict ID */
|
||||
const BYTE* const dictEnd = dictPtr + dictSize;
|
||||
dictPtr += 8;
|
||||
@@ -2924,16 +2934,16 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
|
||||
}
|
||||
|
||||
{ unsigned offcodeLog;
|
||||
size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
|
||||
size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
|
||||
RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");
|
||||
RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");
|
||||
/* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
|
||||
/* fill all offset symbols to avoid garbage at end of table */
|
||||
RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
|
||||
bs->entropy.fse.offcodeCTable,
|
||||
offcodeNCount, MaxOff, offcodeLog,
|
||||
workspace, HUF_WORKSPACE_SIZE)),
|
||||
dictionary_corrupted, "");
|
||||
/* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
|
||||
dictPtr += offcodeHeaderSize;
|
||||
}
|
||||
|
||||
@@ -2942,13 +2952,12 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
|
||||
size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
|
||||
RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");
|
||||
RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, "");
|
||||
/* Every match length code must have non-zero probability */
|
||||
FORWARD_IF_ERROR( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML), "");
|
||||
RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
|
||||
bs->entropy.fse.matchlengthCTable,
|
||||
matchlengthNCount, matchlengthMaxValue, matchlengthLog,
|
||||
workspace, HUF_WORKSPACE_SIZE)),
|
||||
dictionary_corrupted, "");
|
||||
bs->entropy.fse.matchlength_repeatMode = ZSTD_dictNCountRepeat(matchlengthNCount, matchlengthMaxValue, MaxML);
|
||||
dictPtr += matchlengthHeaderSize;
|
||||
}
|
||||
|
||||
@@ -2957,13 +2966,12 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
|
||||
size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
|
||||
RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");
|
||||
RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, "");
|
||||
/* Every literal length code must have non-zero probability */
|
||||
FORWARD_IF_ERROR( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL), "");
|
||||
RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
|
||||
bs->entropy.fse.litlengthCTable,
|
||||
litlengthNCount, litlengthMaxValue, litlengthLog,
|
||||
workspace, HUF_WORKSPACE_SIZE)),
|
||||
dictionary_corrupted, "");
|
||||
bs->entropy.fse.litlength_repeatMode = ZSTD_dictNCountRepeat(litlengthNCount, litlengthMaxValue, MaxLL);
|
||||
dictPtr += litlengthHeaderSize;
|
||||
}
|
||||
|
||||
@@ -2973,6 +2981,22 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
|
||||
bs->rep[2] = MEM_readLE32(dictPtr+8);
|
||||
dictPtr += 12;
|
||||
|
||||
{ size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
|
||||
U32 offcodeMax = MaxOff;
|
||||
if (dictContentSize <= ((U32)-1) - 128 KB) {
|
||||
U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
|
||||
offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
|
||||
}
|
||||
/* All offset values <= dictContentSize + 128 KB must be representable for a valid table */
|
||||
bs->entropy.fse.offcode_repeatMode = ZSTD_dictNCountRepeat(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff));
|
||||
|
||||
/* All repCodes must be <= dictContentSize and != 0 */
|
||||
{ U32 u;
|
||||
for (u=0; u<3; u++) {
|
||||
RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, "");
|
||||
RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, "");
|
||||
} } }
|
||||
|
||||
return dictPtr - (const BYTE*)dict;
|
||||
}
|
||||
|
||||
@@ -2995,8 +3019,6 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
|
||||
{
|
||||
const BYTE* dictPtr = (const BYTE*)dict;
|
||||
const BYTE* const dictEnd = dictPtr + dictSize;
|
||||
short offcodeNCount[MaxOff+1];
|
||||
unsigned offcodeMaxValue = MaxOff;
|
||||
size_t dictID;
|
||||
size_t eSize;
|
||||
|
||||
@@ -3005,32 +3027,16 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
|
||||
assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY);
|
||||
|
||||
dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr + 4 /* skip magic number */ );
|
||||
eSize = ZSTD_loadCEntropy(bs, workspace, offcodeNCount, &offcodeMaxValue, dict, dictSize);
|
||||
eSize = ZSTD_loadCEntropy(bs, workspace, dict, dictSize);
|
||||
FORWARD_IF_ERROR(eSize, "ZSTD_loadCEntropy failed");
|
||||
dictPtr += eSize;
|
||||
|
||||
{ size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
|
||||
U32 offcodeMax = MaxOff;
|
||||
if (dictContentSize <= ((U32)-1) - 128 KB) {
|
||||
U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
|
||||
offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
|
||||
}
|
||||
/* All offset values <= dictContentSize + 128 KB must be representable */
|
||||
FORWARD_IF_ERROR(ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)), "");
|
||||
/* All repCodes must be <= dictContentSize and != 0*/
|
||||
{ U32 u;
|
||||
for (u=0; u<3; u++) {
|
||||
RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, "");
|
||||
RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, "");
|
||||
} }
|
||||
|
||||
bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid;
|
||||
bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid;
|
||||
bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid;
|
||||
{
|
||||
size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
|
||||
FORWARD_IF_ERROR(ZSTD_loadDictionaryContent(
|
||||
ms, NULL, ws, params, dictPtr, dictContentSize, dtlm), "");
|
||||
return dictID;
|
||||
}
|
||||
return dictID;
|
||||
}
|
||||
|
||||
/** ZSTD_compress_insertDictionary() :
|
||||
|
||||
@@ -1045,7 +1045,6 @@ MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max)
|
||||
* assumptions : magic number supposed already checked
|
||||
* and dictSize >= 8 */
|
||||
size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
|
||||
short* offcodeNCount, unsigned* offcodeMaxValue,
|
||||
const void* const dict, size_t dictSize);
|
||||
|
||||
void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs);
|
||||
|
||||
@@ -603,7 +603,7 @@ static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type,
|
||||
const BYTE* codeTable, unsigned maxCode,
|
||||
size_t nbSeq, const FSE_CTable* fseCTable,
|
||||
const U32* additionalBits,
|
||||
short const* defaultNorm, U32 defaultNormLog,
|
||||
short const* defaultNorm, U32 defaultNormLog, U32 defaultMax,
|
||||
void* workspace, size_t wkspSize)
|
||||
{
|
||||
unsigned* const countWksp = (unsigned*)workspace;
|
||||
@@ -615,7 +615,11 @@ static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type,
|
||||
|
||||
HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */
|
||||
if (type == set_basic) {
|
||||
cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max);
|
||||
/* We selected this encoding type, so it must be valid. */
|
||||
assert(max <= defaultMax);
|
||||
cSymbolTypeSizeEstimateInBits = max <= defaultMax
|
||||
? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max)
|
||||
: ERROR(GENERIC);
|
||||
} else if (type == set_rle) {
|
||||
cSymbolTypeSizeEstimateInBits = 0;
|
||||
} else if (type == set_compressed || type == set_repeat) {
|
||||
@@ -643,15 +647,15 @@ static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable,
|
||||
size_t cSeqSizeEstimate = 0;
|
||||
cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, MaxOff,
|
||||
nbSeq, fseTables->offcodeCTable, NULL,
|
||||
OF_defaultNorm, OF_defaultNormLog,
|
||||
OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
|
||||
workspace, wkspSize);
|
||||
cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->llType, llCodeTable, MaxLL,
|
||||
nbSeq, fseTables->litlengthCTable, LL_bits,
|
||||
LL_defaultNorm, LL_defaultNormLog,
|
||||
LL_defaultNorm, LL_defaultNormLog, MaxLL,
|
||||
workspace, wkspSize);
|
||||
cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, MaxML,
|
||||
nbSeq, fseTables->matchlengthCTable, ML_bits,
|
||||
ML_defaultNorm, ML_defaultNormLog,
|
||||
ML_defaultNorm, ML_defaultNormLog, MaxML,
|
||||
workspace, wkspSize);
|
||||
if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize;
|
||||
return cSeqSizeEstimate + sequencesSectionHeaderSize;
|
||||
@@ -809,7 +813,7 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
|
||||
if (sp < send) {
|
||||
seqDef const* seq;
|
||||
repcodes_t rep;
|
||||
memcpy(&rep, prevCBlock->rep, sizeof(rep));
|
||||
memcpy(&rep, prevCBlock->rep, sizeof(rep));
|
||||
for (seq = sstart; seq < sp; ++seq) {
|
||||
rep = ZSTD_updateRep(rep.rep, seq->offset - 1, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0);
|
||||
}
|
||||
|
||||
@@ -483,6 +483,11 @@ MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) {
|
||||
return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace);
|
||||
}
|
||||
|
||||
MEM_STATIC size_t ZSTD_cwksp_used(const ZSTD_cwksp* ws) {
|
||||
return (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->workspace)
|
||||
+ (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->allocStart);
|
||||
}
|
||||
|
||||
MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
|
||||
return ws->allocFailed;
|
||||
}
|
||||
|
||||
@@ -721,7 +721,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
||||
decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);
|
||||
if (ZSTD_isError(decodedSize)) return decodedSize;
|
||||
|
||||
assert(decodedSize <=- dstCapacity);
|
||||
assert(decodedSize <= dstCapacity);
|
||||
dst = (BYTE*)dst + decodedSize;
|
||||
dstCapacity -= decodedSize;
|
||||
|
||||
@@ -1524,7 +1524,7 @@ static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const ne
|
||||
{
|
||||
if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize))
|
||||
zds->oversizedDuration++;
|
||||
else
|
||||
else
|
||||
zds->oversizedDuration = 0;
|
||||
}
|
||||
|
||||
@@ -1731,7 +1731,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
|
||||
{ int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize);
|
||||
int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds);
|
||||
|
||||
|
||||
if (tooSmall || tooLarge) {
|
||||
size_t const bufferSize = neededInBuffSize + neededOutBuffSize;
|
||||
DEBUGLOG(4, "inBuff : from %u to %u",
|
||||
|
||||
@@ -948,7 +948,7 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c
|
||||
}
|
||||
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
static int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd)
|
||||
MEM_STATIC int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd)
|
||||
{
|
||||
size_t const windowSize = dctx->fParams.windowSize;
|
||||
/* No dictionary used. */
|
||||
@@ -969,6 +969,7 @@ MEM_STATIC void ZSTD_assertValidSequence(
|
||||
seq_t const seq,
|
||||
BYTE const* prefixStart, BYTE const* virtualStart)
|
||||
{
|
||||
#if DEBUGLEVEL >= 1
|
||||
size_t const windowSize = dctx->fParams.windowSize;
|
||||
size_t const sequenceSize = seq.litLength + seq.matchLength;
|
||||
BYTE const* const oLitEnd = op + seq.litLength;
|
||||
@@ -986,6 +987,9 @@ MEM_STATIC void ZSTD_assertValidSequence(
|
||||
/* Offset must be within our window. */
|
||||
assert(seq.offset <= windowSize);
|
||||
}
|
||||
#else
|
||||
(void)dctx, (void)op, (void)oend, (void)seq, (void)prefixStart, (void)virtualStart;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+22
-13
@@ -40,23 +40,33 @@
|
||||
* Constants
|
||||
***************************************/
|
||||
#define COVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB))
|
||||
#define DEFAULT_SPLITPOINT 1.0
|
||||
#define COVER_DEFAULT_SPLITPOINT 1.0
|
||||
|
||||
/*-*************************************
|
||||
* Console display
|
||||
***************************************/
|
||||
#ifndef LOCALDISPLAYLEVEL
|
||||
static int g_displayLevel = 2;
|
||||
#endif
|
||||
#undef DISPLAY
|
||||
#define DISPLAY(...) \
|
||||
{ \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fflush(stderr); \
|
||||
}
|
||||
#undef LOCALDISPLAYLEVEL
|
||||
#define LOCALDISPLAYLEVEL(displayLevel, l, ...) \
|
||||
if (displayLevel >= l) { \
|
||||
DISPLAY(__VA_ARGS__); \
|
||||
} /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */
|
||||
#undef DISPLAYLEVEL
|
||||
#define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__)
|
||||
|
||||
#ifndef LOCALDISPLAYUPDATE
|
||||
static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;
|
||||
static clock_t g_time = 0;
|
||||
#endif
|
||||
#undef LOCALDISPLAYUPDATE
|
||||
#define LOCALDISPLAYUPDATE(displayLevel, l, ...) \
|
||||
if (displayLevel >= l) { \
|
||||
if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) { \
|
||||
@@ -64,9 +74,8 @@ static int g_displayLevel = 2;
|
||||
DISPLAY(__VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
#undef DISPLAYUPDATE
|
||||
#define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__)
|
||||
static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;
|
||||
static clock_t g_time = 0;
|
||||
|
||||
/*-*************************************
|
||||
* Hash table
|
||||
@@ -120,9 +129,9 @@ static int COVER_map_init(COVER_map_t *map, U32 size) {
|
||||
/**
|
||||
* Internal hash function
|
||||
*/
|
||||
static const U32 prime4bytes = 2654435761U;
|
||||
static const U32 COVER_prime4bytes = 2654435761U;
|
||||
static U32 COVER_map_hash(COVER_map_t *map, U32 key) {
|
||||
return (key * prime4bytes) >> (32 - map->sizeLog);
|
||||
return (key * COVER_prime4bytes) >> (32 - map->sizeLog);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,7 +224,7 @@ typedef struct {
|
||||
} COVER_ctx_t;
|
||||
|
||||
/* We need a global context for qsort... */
|
||||
static COVER_ctx_t *g_ctx = NULL;
|
||||
static COVER_ctx_t *g_coverCtx = NULL;
|
||||
|
||||
/*-*************************************
|
||||
* Helper functions
|
||||
@@ -258,11 +267,11 @@ static int COVER_cmp8(COVER_ctx_t *ctx, const void *lp, const void *rp) {
|
||||
|
||||
/**
|
||||
* Same as COVER_cmp() except ties are broken by pointer value
|
||||
* NOTE: g_ctx must be set to call this function. A global is required because
|
||||
* NOTE: g_coverCtx must be set to call this function. A global is required because
|
||||
* qsort doesn't take an opaque pointer.
|
||||
*/
|
||||
static int COVER_strict_cmp(const void *lp, const void *rp) {
|
||||
int result = COVER_cmp(g_ctx, lp, rp);
|
||||
static int WIN_CDECL COVER_strict_cmp(const void *lp, const void *rp) {
|
||||
int result = COVER_cmp(g_coverCtx, lp, rp);
|
||||
if (result == 0) {
|
||||
result = lp < rp ? -1 : 1;
|
||||
}
|
||||
@@ -271,8 +280,8 @@ static int COVER_strict_cmp(const void *lp, const void *rp) {
|
||||
/**
|
||||
* Faster version for d <= 8.
|
||||
*/
|
||||
static int COVER_strict_cmp8(const void *lp, const void *rp) {
|
||||
int result = COVER_cmp8(g_ctx, lp, rp);
|
||||
static int WIN_CDECL COVER_strict_cmp8(const void *lp, const void *rp) {
|
||||
int result = COVER_cmp8(g_coverCtx, lp, rp);
|
||||
if (result == 0) {
|
||||
result = lp < rp ? -1 : 1;
|
||||
}
|
||||
@@ -603,7 +612,7 @@ static size_t COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer,
|
||||
/* qsort doesn't take an opaque pointer, so pass as a global.
|
||||
* On OpenBSD qsort() is not guaranteed to be stable, their mergesort() is.
|
||||
*/
|
||||
g_ctx = ctx;
|
||||
g_coverCtx = ctx;
|
||||
#if defined(__OpenBSD__)
|
||||
mergesort(ctx->suffix, ctx->suffixSize, sizeof(U32),
|
||||
(ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp));
|
||||
@@ -1106,7 +1115,7 @@ ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
|
||||
/* constants */
|
||||
const unsigned nbThreads = parameters->nbThreads;
|
||||
const double splitPoint =
|
||||
parameters->splitPoint <= 0.0 ? DEFAULT_SPLITPOINT : parameters->splitPoint;
|
||||
parameters->splitPoint <= 0.0 ? COVER_DEFAULT_SPLITPOINT : parameters->splitPoint;
|
||||
const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d;
|
||||
const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d;
|
||||
const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k;
|
||||
|
||||
+18
-17
@@ -21,6 +21,7 @@
|
||||
#include "../common/threading.h"
|
||||
#include "cover.h"
|
||||
#include "../common/zstd_internal.h" /* includes zstd.h */
|
||||
#include "../compress/zstd_compress_internal.h" /* ZSTD_hash*() */
|
||||
#ifndef ZDICT_STATIC_LINKING_ONLY
|
||||
#define ZDICT_STATIC_LINKING_ONLY
|
||||
#endif
|
||||
@@ -33,7 +34,7 @@
|
||||
#define FASTCOVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB))
|
||||
#define FASTCOVER_MAX_F 31
|
||||
#define FASTCOVER_MAX_ACCEL 10
|
||||
#define DEFAULT_SPLITPOINT 0.75
|
||||
#define FASTCOVER_DEFAULT_SPLITPOINT 0.75
|
||||
#define DEFAULT_F 20
|
||||
#define DEFAULT_ACCEL 1
|
||||
|
||||
@@ -41,18 +42,28 @@
|
||||
/*-*************************************
|
||||
* Console display
|
||||
***************************************/
|
||||
#ifndef LOCALDISPLAYLEVEL
|
||||
static int g_displayLevel = 2;
|
||||
#endif
|
||||
#undef DISPLAY
|
||||
#define DISPLAY(...) \
|
||||
{ \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fflush(stderr); \
|
||||
}
|
||||
#undef LOCALDISPLAYLEVEL
|
||||
#define LOCALDISPLAYLEVEL(displayLevel, l, ...) \
|
||||
if (displayLevel >= l) { \
|
||||
DISPLAY(__VA_ARGS__); \
|
||||
} /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */
|
||||
#undef DISPLAYLEVEL
|
||||
#define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__)
|
||||
|
||||
#ifndef LOCALDISPLAYUPDATE
|
||||
static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;
|
||||
static clock_t g_time = 0;
|
||||
#endif
|
||||
#undef LOCALDISPLAYUPDATE
|
||||
#define LOCALDISPLAYUPDATE(displayLevel, l, ...) \
|
||||
if (displayLevel >= l) { \
|
||||
if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) { \
|
||||
@@ -60,31 +71,21 @@ static int g_displayLevel = 2;
|
||||
DISPLAY(__VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
#undef DISPLAYUPDATE
|
||||
#define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__)
|
||||
static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;
|
||||
static clock_t g_time = 0;
|
||||
|
||||
|
||||
/*-*************************************
|
||||
* Hash Functions
|
||||
***************************************/
|
||||
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 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); }
|
||||
|
||||
|
||||
/**
|
||||
* Hash the d-byte value pointed to by p and mod 2^f
|
||||
* Hash the d-byte value pointed to by p and mod 2^f into the frequency vector
|
||||
*/
|
||||
static size_t FASTCOVER_hashPtrToIndex(const void* p, U32 h, unsigned d) {
|
||||
static size_t FASTCOVER_hashPtrToIndex(const void* p, U32 f, unsigned d) {
|
||||
if (d == 6) {
|
||||
return ZSTD_hash6Ptr(p, h) & ((1 << h) - 1);
|
||||
return ZSTD_hash6Ptr(p, f);
|
||||
}
|
||||
return ZSTD_hash8Ptr(p, h) & ((1 << h) - 1);
|
||||
return ZSTD_hash8Ptr(p, f);
|
||||
}
|
||||
|
||||
|
||||
@@ -617,7 +618,7 @@ ZDICT_optimizeTrainFromBuffer_fastCover(
|
||||
/* constants */
|
||||
const unsigned nbThreads = parameters->nbThreads;
|
||||
const double splitPoint =
|
||||
parameters->splitPoint <= 0.0 ? DEFAULT_SPLITPOINT : parameters->splitPoint;
|
||||
parameters->splitPoint <= 0.0 ? FASTCOVER_DEFAULT_SPLITPOINT : parameters->splitPoint;
|
||||
const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d;
|
||||
const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d;
|
||||
const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k;
|
||||
|
||||
@@ -69,7 +69,9 @@ static const U32 g_selectivity_default = 9;
|
||||
/*-*************************************
|
||||
* Console display
|
||||
***************************************/
|
||||
#undef DISPLAY
|
||||
#define DISPLAY(...) { fprintf(stderr, __VA_ARGS__); fflush( stderr ); }
|
||||
#undef DISPLAYLEVEL
|
||||
#define DISPLAYLEVEL(l, ...) if (notificationLevel>=l) { DISPLAY(__VA_ARGS__); } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */
|
||||
|
||||
static clock_t ZDICT_clockSpan(clock_t nPrevious) { return clock() - nPrevious; }
|
||||
@@ -105,20 +107,17 @@ size_t ZDICT_getDictHeaderSize(const void* dictBuffer, size_t dictSize)
|
||||
size_t headerSize;
|
||||
if (dictSize <= 8 || MEM_readLE32(dictBuffer) != ZSTD_MAGIC_DICTIONARY) return ERROR(dictionary_corrupted);
|
||||
|
||||
{ unsigned offcodeMaxValue = MaxOff;
|
||||
ZSTD_compressedBlockState_t* bs = (ZSTD_compressedBlockState_t*)malloc(sizeof(ZSTD_compressedBlockState_t));
|
||||
{ ZSTD_compressedBlockState_t* bs = (ZSTD_compressedBlockState_t*)malloc(sizeof(ZSTD_compressedBlockState_t));
|
||||
U32* wksp = (U32*)malloc(HUF_WORKSPACE_SIZE);
|
||||
short* offcodeNCount = (short*)malloc((MaxOff+1)*sizeof(short));
|
||||
if (!bs || !wksp || !offcodeNCount) {
|
||||
if (!bs || !wksp) {
|
||||
headerSize = ERROR(memory_allocation);
|
||||
} else {
|
||||
ZSTD_reset_compressedBlockState(bs);
|
||||
headerSize = ZSTD_loadCEntropy(bs, wksp, offcodeNCount, &offcodeMaxValue, dictBuffer, dictSize);
|
||||
headerSize = ZSTD_loadCEntropy(bs, wksp, dictBuffer, dictSize);
|
||||
}
|
||||
|
||||
free(bs);
|
||||
free(wksp);
|
||||
free(offcodeNCount);
|
||||
}
|
||||
|
||||
return headerSize;
|
||||
@@ -532,6 +531,7 @@ static size_t ZDICT_trainBuffer_legacy(dictItem* dictList, U32 dictListSize,
|
||||
clock_t displayClock = 0;
|
||||
clock_t const refreshRate = CLOCKS_PER_SEC * 3 / 10;
|
||||
|
||||
# undef DISPLAYUPDATE
|
||||
# define DISPLAYUPDATE(l, ...) if (notificationLevel>=l) { \
|
||||
if (ZDICT_clockSpan(displayClock) > refreshRate) \
|
||||
{ displayClock = clock(); DISPLAY(__VA_ARGS__); \
|
||||
|
||||
@@ -74,7 +74,7 @@ extern "C" {
|
||||
/*-*************************************
|
||||
* Debug
|
||||
***************************************/
|
||||
#include "debug.h"
|
||||
#include "../common/debug.h"
|
||||
#ifndef assert
|
||||
# define assert(condition) ((void)0)
|
||||
#endif
|
||||
|
||||
+9
-5
@@ -365,16 +365,20 @@ typedef enum {
|
||||
ZSTD_c_dictIDFlag=202, /* When applicable, dictionary's ID is written into frame header (default:1) */
|
||||
|
||||
/* multi-threading parameters */
|
||||
/* These parameters are only useful if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD).
|
||||
* They return an error otherwise. */
|
||||
/* These parameters are only active if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD).
|
||||
* Otherwise, trying to set any other value than default (0) will be a no-op and return an error.
|
||||
* In a situation where it's unknown if the linked library supports multi-threading or not,
|
||||
* setting ZSTD_c_nbWorkers to any value >= 1 and consulting the return value provides a quick way to check this property.
|
||||
*/
|
||||
ZSTD_c_nbWorkers=400, /* Select how many threads will be spawned to compress in parallel.
|
||||
* When nbWorkers >= 1, triggers asynchronous mode when used with ZSTD_compressStream*() :
|
||||
* When nbWorkers >= 1, triggers asynchronous mode when invoking ZSTD_compressStream*() :
|
||||
* ZSTD_compressStream*() consumes input and flush output if possible, but immediately gives back control to caller,
|
||||
* while compression work is performed in parallel, within worker threads.
|
||||
* while compression is performed in parallel, within worker thread(s).
|
||||
* (note : a strong exception to this rule is when first invocation of ZSTD_compressStream2() sets ZSTD_e_end :
|
||||
* in which case, ZSTD_compressStream2() delegates to ZSTD_compress2(), which is always a blocking call).
|
||||
* More workers improve speed, but also increase memory usage.
|
||||
* Default value is `0`, aka "single-threaded mode" : no worker is spawned, compression is performed inside Caller's thread, all invocations are blocking */
|
||||
* Default value is `0`, aka "single-threaded mode" : no worker is spawned,
|
||||
* compression is performed inside Caller's thread, and all invocations are blocking */
|
||||
ZSTD_c_jobSize=401, /* Size of a compression job. This value is enforced only when nbWorkers >= 1.
|
||||
* Each compression job is completed in parallel, so this value can indirectly impact the nb of active threads.
|
||||
* 0 means default, which is dynamically determined based on compression parameters.
|
||||
|
||||
+1
-1
@@ -227,7 +227,7 @@ zstd-dll : $(ZSTD_CLI_OBJ)
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT) $(LDFLAGS)
|
||||
|
||||
|
||||
## zstd-pgo: zstd executable optimized with pgo. `gcc` only.
|
||||
## zstd-pgo: zstd executable optimized with PGO.
|
||||
zstd-pgo :
|
||||
$(MAKE) clean
|
||||
$(MAKE) zstd MOREFLAGS=-fprofile-generate
|
||||
|
||||
+52
-21
@@ -624,7 +624,6 @@ FIO_openDstFile(FIO_prefs_t* const prefs,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! FIO_createDictBuffer() :
|
||||
* creates a buffer, pointed by `*bufferPtr`,
|
||||
* loads `filename` content into it, up to DICTSIZE_MAX bytes.
|
||||
@@ -669,15 +668,9 @@ static size_t FIO_createDictBuffer(void** bufferPtr, const char* fileName, FIO_p
|
||||
* Checks for and warns if there are any files that would have the same output path
|
||||
*/
|
||||
int FIO_checkFilenameCollisions(const char** filenameTable, unsigned nbFiles) {
|
||||
const char **filenameTableSorted, *c, *prevElem, *filename;
|
||||
const char **filenameTableSorted, *prevElem, *filename;
|
||||
unsigned u;
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__) || defined (__MSVCRT__) /* windows support */
|
||||
c = "\\";
|
||||
#else
|
||||
c = "/";
|
||||
#endif
|
||||
|
||||
filenameTableSorted = (const char**) malloc(sizeof(char*) * nbFiles);
|
||||
if (!filenameTableSorted) {
|
||||
DISPLAY("Unable to malloc new str array, not checking for name collisions\n");
|
||||
@@ -685,7 +678,7 @@ int FIO_checkFilenameCollisions(const char** filenameTable, unsigned nbFiles) {
|
||||
}
|
||||
|
||||
for (u = 0; u < nbFiles; ++u) {
|
||||
filename = strrchr(filenameTable[u], c[0]);
|
||||
filename = strrchr(filenameTable[u], PATH_SEP);
|
||||
if (filename == NULL) {
|
||||
filenameTableSorted[u] = filenameTable[u];
|
||||
} else {
|
||||
@@ -771,9 +764,12 @@ static void FIO_adjustMemLimitForPatchFromMode(FIO_prefs_t* const prefs,
|
||||
unsigned long long const maxSrcFileSize)
|
||||
{
|
||||
unsigned long long maxSize = MAX(prefs->memLimit, MAX(dictSize, maxSrcFileSize));
|
||||
unsigned const maxWindowSize = (1U << ZSTD_WINDOWLOG_MAX);
|
||||
if (maxSize == UTIL_FILESIZE_UNKNOWN)
|
||||
EXM_THROW(42, "Using --patch-from with stdin requires --stream-size");
|
||||
assert(maxSize != UTIL_FILESIZE_UNKNOWN);
|
||||
if (maxSize > UINT_MAX)
|
||||
EXM_THROW(42, "Can't handle files larger than %u GB\n", UINT_MAX/(1 GB) + 1);
|
||||
if (maxSize > maxWindowSize)
|
||||
EXM_THROW(42, "Can't handle files larger than %u GB\n", maxWindowSize/(1 GB));
|
||||
FIO_setMemLimit(prefs, (unsigned)maxSize);
|
||||
}
|
||||
|
||||
@@ -809,7 +805,7 @@ static void FIO_adjustParamsForPatchFromMode(FIO_prefs_t* const prefs,
|
||||
comprParams->windowLog = MIN(ZSTD_WINDOWLOG_MAX, fileWindowLog);
|
||||
if (fileWindowLog > ZSTD_cycleLog(cParams.hashLog, cParams.strategy)) {
|
||||
if (!prefs->ldmFlag)
|
||||
DISPLAYLEVEL(1, "long mode automaticaly triggered\n");
|
||||
DISPLAYLEVEL(1, "long mode automatically triggered\n");
|
||||
FIO_setLdmFlag(prefs, 1);
|
||||
}
|
||||
if (cParams.strategy >= ZSTD_btopt) {
|
||||
@@ -838,8 +834,10 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs,
|
||||
|
||||
/* need to update memLimit before calling createDictBuffer
|
||||
* because of memLimit check inside it */
|
||||
if (prefs->patchFromMode)
|
||||
FIO_adjustParamsForPatchFromMode(prefs, &comprParams, UTIL_getFileSize(dictFileName), maxSrcFileSize, cLevel);
|
||||
if (prefs->patchFromMode) {
|
||||
unsigned long long const ssSize = (unsigned long long)prefs->streamSrcSize;
|
||||
FIO_adjustParamsForPatchFromMode(prefs, &comprParams, UTIL_getFileSize(dictFileName), ssSize > 0 ? ssSize : maxSrcFileSize, cLevel);
|
||||
}
|
||||
ress.dstBuffer = malloc(ress.dstBufferSize);
|
||||
ress.dictBufferSize = FIO_createDictBuffer(&ress.dictBuffer, dictFileName, prefs); /* works with dictFileName==NULL */
|
||||
if (!ress.srcBuffer || !ress.dstBuffer)
|
||||
@@ -1505,7 +1503,7 @@ static int FIO_compressFilename_dstFile(FIO_prefs_t* const prefs,
|
||||
} else if ( strcmp(dstFileName, stdoutmark)
|
||||
&& strcmp(dstFileName, nulmark)
|
||||
&& transfer_permissions) {
|
||||
DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: transfering permissions into dst: %s \n", dstFileName);
|
||||
DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: transferring permissions into dst: %s \n", dstFileName);
|
||||
UTIL_setFileStat(dstFileName, &statbuf);
|
||||
} else {
|
||||
DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: do not transfer permissions into dst: %s \n", dstFileName);
|
||||
@@ -1594,6 +1592,7 @@ int FIO_compressFilename(FIO_prefs_t* const prefs, const char* dstFileName,
|
||||
cRess_t const ress = FIO_createCResources(prefs, dictFileName, UTIL_getFileSize(srcFileName), compressionLevel, comprParams);
|
||||
int const result = FIO_compressFilename_srcFile(prefs, ress, dstFileName, srcFileName, compressionLevel);
|
||||
|
||||
#define DISPLAY_LEVEL_DEFAULT 2
|
||||
|
||||
FIO_freeCResources(ress);
|
||||
return result;
|
||||
@@ -1658,6 +1657,7 @@ static unsigned long long FIO_getLargestFileSize(const char** inFileNames, unsig
|
||||
*/
|
||||
int FIO_compressMultipleFilenames(FIO_prefs_t* const prefs,
|
||||
const char** inFileNamesTable, unsigned nbFiles,
|
||||
const char* outMirroredRootDirName,
|
||||
const char* outDirName,
|
||||
const char* outFileName, const char* suffix,
|
||||
const char* dictFileName, int compressionLevel,
|
||||
@@ -1684,12 +1684,30 @@ int FIO_compressMultipleFilenames(FIO_prefs_t* const prefs,
|
||||
ress.dstFile = NULL;
|
||||
}
|
||||
} else {
|
||||
unsigned u;
|
||||
unsigned int u=0;
|
||||
if (outMirroredRootDirName)
|
||||
UTIL_mirrorSourceFilesDirectories(inFileNamesTable, nbFiles, outMirroredRootDirName);
|
||||
|
||||
for (u=0; u<nbFiles; u++) {
|
||||
const char* const srcFileName = inFileNamesTable[u];
|
||||
const char* const dstFileName = FIO_determineCompressedName(srcFileName, outDirName, suffix); /* cannot fail */
|
||||
const char* dstFileName = NULL;
|
||||
if (outMirroredRootDirName) {
|
||||
char* validMirroredDirName = UTIL_createMirroredDestDirName(srcFileName, outMirroredRootDirName);
|
||||
if (validMirroredDirName) {
|
||||
dstFileName = FIO_determineCompressedName(srcFileName, validMirroredDirName, suffix);
|
||||
free(validMirroredDirName);
|
||||
} else {
|
||||
DISPLAYLEVEL(2, "zstd: --output-dir-mirror cannot compress '%s' into '%s' \n", srcFileName, outMirroredRootDirName);
|
||||
error=1;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
dstFileName = FIO_determineCompressedName(srcFileName, outDirName, suffix); /* cannot fail */
|
||||
}
|
||||
|
||||
error |= FIO_compressFilename_srcFile(prefs, ress, dstFileName, srcFileName, compressionLevel);
|
||||
}
|
||||
|
||||
if (outDirName)
|
||||
FIO_checkFilenameCollisions(inFileNamesTable ,nbFiles);
|
||||
}
|
||||
@@ -2531,10 +2549,10 @@ FIO_determineDstName(const char* srcFileName, const char* outDirName)
|
||||
/* note : dstFileNameBuffer memory is not going to be free */
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
FIO_decompressMultipleFilenames(FIO_prefs_t* const prefs,
|
||||
const char** srcNamesTable, unsigned nbFiles,
|
||||
const char* outMirroredRootDirName,
|
||||
const char* outDirName, const char* outFileName,
|
||||
const char* dictFileName)
|
||||
{
|
||||
@@ -2553,12 +2571,25 @@ FIO_decompressMultipleFilenames(FIO_prefs_t* const prefs,
|
||||
EXM_THROW(72, "Write error : %s : cannot properly close output file",
|
||||
strerror(errno));
|
||||
} else {
|
||||
unsigned u;
|
||||
unsigned int u = 0;
|
||||
if (outMirroredRootDirName)
|
||||
UTIL_mirrorSourceFilesDirectories(srcNamesTable, nbFiles, outMirroredRootDirName);
|
||||
|
||||
for (u=0; u<nbFiles; u++) { /* create dstFileName */
|
||||
const char* const srcFileName = srcNamesTable[u];
|
||||
const char* const dstFileName = FIO_determineDstName(srcFileName, outDirName);
|
||||
const char* dstFileName = NULL;
|
||||
if (outMirroredRootDirName) {
|
||||
char* validMirroredDirName = UTIL_createMirroredDestDirName(srcFileName, outMirroredRootDirName);
|
||||
if (validMirroredDirName) {
|
||||
dstFileName = FIO_determineDstName(srcFileName, validMirroredDirName);
|
||||
free(validMirroredDirName);
|
||||
} else {
|
||||
DISPLAYLEVEL(2, "zstd: --output-dir-mirror cannot decompress '%s' into '%s'\n", srcFileName, outMirroredRootDirName);
|
||||
}
|
||||
} else {
|
||||
dstFileName = FIO_determineDstName(srcFileName, outDirName);
|
||||
}
|
||||
if (dstFileName == NULL) { error=1; continue; }
|
||||
|
||||
error |= FIO_decompressSrcFile(prefs, ress, dstFileName, srcFileName);
|
||||
}
|
||||
if (outDirName)
|
||||
|
||||
@@ -122,6 +122,7 @@ int FIO_listMultipleFiles(unsigned numFiles, const char** filenameTable, int dis
|
||||
* @return : nb of missing files */
|
||||
int FIO_compressMultipleFilenames(FIO_prefs_t* const prefs,
|
||||
const char** inFileNamesTable, unsigned nbFiles,
|
||||
const char* outMirroredDirName,
|
||||
const char* outDirName,
|
||||
const char* outFileName, const char* suffix,
|
||||
const char* dictFileName, int compressionLevel,
|
||||
@@ -131,6 +132,7 @@ int FIO_compressMultipleFilenames(FIO_prefs_t* const prefs,
|
||||
* @return : nb of missing or skipped files */
|
||||
int FIO_decompressMultipleFilenames(FIO_prefs_t* const prefs,
|
||||
const char** srcNamesTable, unsigned nbFiles,
|
||||
const char* outMirroredDirName,
|
||||
const char* outDirName,
|
||||
const char* outFileName,
|
||||
const char* dictFileName);
|
||||
|
||||
+294
-9
@@ -45,7 +45,6 @@ extern "C" {
|
||||
# include <string.h> /* strerror, memcpy */
|
||||
#endif /* #ifdef _WIN32 */
|
||||
|
||||
|
||||
/*-****************************************
|
||||
* Internal Macros
|
||||
******************************************/
|
||||
@@ -130,6 +129,18 @@ int UTIL_getFileStat(const char* infilename, stat_t *statbuf)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int UTIL_getDirectoryStat(const char* infilename, stat_t *statbuf)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
int const r = _stat64(infilename, statbuf);
|
||||
if (!r && (statbuf->st_mode & _S_IFDIR)) return 1;
|
||||
#else
|
||||
int const r = stat(infilename, statbuf);
|
||||
if (!r && S_ISDIR(statbuf->st_mode)) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* like chmod, but avoid changing permission of /dev/null */
|
||||
int UTIL_chmod(char const* filename, mode_t permissions)
|
||||
{
|
||||
@@ -178,14 +189,7 @@ int UTIL_setFileStat(const char *filename, stat_t *statbuf)
|
||||
int UTIL_isDirectory(const char* infilename)
|
||||
{
|
||||
stat_t statbuf;
|
||||
#if defined(_MSC_VER)
|
||||
int const r = _stat64(infilename, &statbuf);
|
||||
if (!r && (statbuf.st_mode & _S_IFDIR)) return 1;
|
||||
#else
|
||||
int const r = stat(infilename, &statbuf);
|
||||
if (!r && S_ISDIR(statbuf.st_mode)) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
return UTIL_getDirectoryStat(infilename, &statbuf);
|
||||
}
|
||||
|
||||
int UTIL_compareStr(const void *p1, const void *p2) {
|
||||
@@ -633,6 +637,287 @@ const char* UTIL_getFileExtension(const char* infilename)
|
||||
return extension;
|
||||
}
|
||||
|
||||
static int pathnameHas2Dots(const char *pathname)
|
||||
{
|
||||
return NULL != strstr(pathname, "..");
|
||||
}
|
||||
|
||||
static int isFileNameValidForMirroredOutput(const char *filename)
|
||||
{
|
||||
return !pathnameHas2Dots(filename);
|
||||
}
|
||||
|
||||
|
||||
#define DIR_DEFAULT_MODE 0755
|
||||
static mode_t getDirMode(const char *dirName)
|
||||
{
|
||||
stat_t st;
|
||||
int ret = UTIL_getDirectoryStat(dirName, &st);
|
||||
if (!ret) {
|
||||
UTIL_DISPLAY("zstd: failed to get DIR stats %s: %s\n", dirName, strerror(errno));
|
||||
return DIR_DEFAULT_MODE;
|
||||
}
|
||||
return st.st_mode;
|
||||
}
|
||||
|
||||
static int makeDir(const char *dir, mode_t mode)
|
||||
{
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__) || defined (__MSVCRT__)
|
||||
int ret = _mkdir(dir);
|
||||
(void) mode;
|
||||
#else
|
||||
int ret = mkdir(dir, mode);
|
||||
#endif
|
||||
if (ret != 0) {
|
||||
if (errno == EEXIST)
|
||||
return 0;
|
||||
UTIL_DISPLAY("zstd: failed to create DIR %s: %s\n", dir, strerror(errno));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* this function requires a mutable input string */
|
||||
static void convertPathnameToDirName(char *pathname)
|
||||
{
|
||||
size_t len = 0;
|
||||
char* pos = NULL;
|
||||
/* get dir name from pathname similar to 'dirname()' */
|
||||
assert(pathname != NULL);
|
||||
|
||||
/* remove trailing '/' chars */
|
||||
len = strlen(pathname);
|
||||
assert(len > 0);
|
||||
while (pathname[len] == PATH_SEP) {
|
||||
pathname[len] = '\0';
|
||||
len--;
|
||||
}
|
||||
if (len == 0) return;
|
||||
|
||||
/* if input is a single file, return '.' instead. i.e.
|
||||
* "xyz/abc/file.txt" => "xyz/abc"
|
||||
"./file.txt" => "."
|
||||
"file.txt" => "."
|
||||
*/
|
||||
pos = strrchr(pathname, PATH_SEP);
|
||||
if (pos == NULL) {
|
||||
pathname[0] = '.';
|
||||
pathname[1] = '\0';
|
||||
} else {
|
||||
*pos = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* pathname must be valid */
|
||||
static const char* trimLeadingRootChar(const char *pathname)
|
||||
{
|
||||
assert(pathname != NULL);
|
||||
if (pathname[0] == PATH_SEP)
|
||||
return pathname + 1;
|
||||
return pathname;
|
||||
}
|
||||
|
||||
/* pathname must be valid */
|
||||
static const char* trimLeadingCurrentDirConst(const char *pathname)
|
||||
{
|
||||
assert(pathname != NULL);
|
||||
if ((pathname[0] == '.') && (pathname[1] == PATH_SEP))
|
||||
return pathname + 2;
|
||||
return pathname;
|
||||
}
|
||||
|
||||
static char*
|
||||
trimLeadingCurrentDir(char *pathname)
|
||||
{
|
||||
/* 'union charunion' can do const-cast without compiler warning */
|
||||
union charunion {
|
||||
char *chr;
|
||||
const char* cchr;
|
||||
} ptr;
|
||||
ptr.cchr = trimLeadingCurrentDirConst(pathname);
|
||||
return ptr.chr;
|
||||
}
|
||||
|
||||
/* remove leading './' or '/' chars here */
|
||||
static const char * trimPath(const char *pathname)
|
||||
{
|
||||
return trimLeadingRootChar(
|
||||
trimLeadingCurrentDirConst(pathname));
|
||||
}
|
||||
|
||||
static char* mallocAndJoin2Dir(const char *dir1, const char *dir2)
|
||||
{
|
||||
const size_t dir1Size = strlen(dir1);
|
||||
const size_t dir2Size = strlen(dir2);
|
||||
char *outDirBuffer, *buffer, trailingChar;
|
||||
|
||||
assert(dir1 != NULL && dir2 != NULL);
|
||||
outDirBuffer = (char *) malloc(dir1Size + dir2Size + 2);
|
||||
CONTROL(outDirBuffer != NULL);
|
||||
|
||||
strncpy(outDirBuffer, dir1, dir1Size);
|
||||
outDirBuffer[dir1Size] = '\0';
|
||||
|
||||
if (dir2[0] == '.')
|
||||
return outDirBuffer;
|
||||
|
||||
buffer = outDirBuffer + dir1Size;
|
||||
trailingChar = *(buffer - 1);
|
||||
if (trailingChar != PATH_SEP) {
|
||||
*buffer = PATH_SEP;
|
||||
buffer++;
|
||||
}
|
||||
strncpy(buffer, dir2, dir2Size);
|
||||
buffer[dir2Size] = '\0';
|
||||
|
||||
return outDirBuffer;
|
||||
}
|
||||
|
||||
/* this function will return NULL if input srcFileName is not valid name for mirrored output path */
|
||||
char* UTIL_createMirroredDestDirName(const char* srcFileName, const char* outDirRootName)
|
||||
{
|
||||
char* pathname = NULL;
|
||||
if (!isFileNameValidForMirroredOutput(srcFileName))
|
||||
return NULL;
|
||||
|
||||
pathname = mallocAndJoin2Dir(outDirRootName, trimPath(srcFileName));
|
||||
|
||||
convertPathnameToDirName(pathname);
|
||||
return pathname;
|
||||
}
|
||||
|
||||
static int
|
||||
mirrorSrcDir(char* srcDirName, const char* outDirName)
|
||||
{
|
||||
mode_t srcMode;
|
||||
int status = 0;
|
||||
char* newDir = mallocAndJoin2Dir(outDirName, trimPath(srcDirName));
|
||||
if (!newDir)
|
||||
return -ENOMEM;
|
||||
|
||||
srcMode = getDirMode(srcDirName);
|
||||
status = makeDir(newDir, srcMode);
|
||||
free(newDir);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
mirrorSrcDirRecursive(char* srcDirName, const char* outDirName)
|
||||
{
|
||||
int status = 0;
|
||||
char* pp = trimLeadingCurrentDir(srcDirName);
|
||||
char* sp = NULL;
|
||||
|
||||
while ((sp = strchr(pp, PATH_SEP)) != NULL) {
|
||||
if (sp != pp) {
|
||||
*sp = '\0';
|
||||
status = mirrorSrcDir(srcDirName, outDirName);
|
||||
if (status != 0)
|
||||
return status;
|
||||
*sp = PATH_SEP;
|
||||
}
|
||||
pp = sp + 1;
|
||||
}
|
||||
status = mirrorSrcDir(srcDirName, outDirName);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
makeMirroredDestDirsWithSameSrcDirMode(char** srcDirNames, unsigned nbFile, const char* outDirName)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (i = 0; i < nbFile; i++)
|
||||
mirrorSrcDirRecursive(srcDirNames[i], outDirName);
|
||||
}
|
||||
|
||||
static int
|
||||
firstIsParentOrSameDirOfSecond(const char* firstDir, const char* secondDir)
|
||||
{
|
||||
size_t firstDirLen = strlen(firstDir),
|
||||
secondDirLen = strlen(secondDir);
|
||||
return firstDirLen <= secondDirLen &&
|
||||
(secondDir[firstDirLen] == PATH_SEP || secondDir[firstDirLen] == '\0') &&
|
||||
0 == strncmp(firstDir, secondDir, firstDirLen);
|
||||
}
|
||||
|
||||
static int compareDir(const void* pathname1, const void* pathname2) {
|
||||
/* sort it after remove the leading '/' or './'*/
|
||||
const char* s1 = trimPath(*(char * const *) pathname1);
|
||||
const char* s2 = trimPath(*(char * const *) pathname2);
|
||||
return strcmp(s1, s2);
|
||||
}
|
||||
|
||||
static void
|
||||
makeUniqueMirroredDestDirs(char** srcDirNames, unsigned nbFile, const char* outDirName)
|
||||
{
|
||||
unsigned int i = 0, uniqueDirNr = 0;
|
||||
char** uniqueDirNames = NULL;
|
||||
|
||||
if (nbFile == 0)
|
||||
return;
|
||||
|
||||
uniqueDirNames = (char** ) malloc(nbFile * sizeof (char *));
|
||||
CONTROL(uniqueDirNames != NULL);
|
||||
|
||||
/* if dirs is "a/b/c" and "a/b/c/d", we only need call:
|
||||
* we just need "a/b/c/d" */
|
||||
qsort((void *)srcDirNames, nbFile, sizeof(char*), compareDir);
|
||||
|
||||
uniqueDirNr = 1;
|
||||
uniqueDirNames[uniqueDirNr - 1] = srcDirNames[0];
|
||||
for (i = 1; i < nbFile; i++) {
|
||||
char* prevDirName = srcDirNames[i - 1];
|
||||
char* currDirName = srcDirNames[i];
|
||||
|
||||
/* note: we alwasy compare trimmed path, i.e.:
|
||||
* src dir of "./foo" and "/foo" will be both saved into:
|
||||
* "outDirName/foo/" */
|
||||
if (!firstIsParentOrSameDirOfSecond(trimPath(prevDirName),
|
||||
trimPath(currDirName)))
|
||||
uniqueDirNr++;
|
||||
|
||||
/* we need maintain original src dir name instead of trimmed
|
||||
* dir, so we can retrive the original src dir's mode_t */
|
||||
uniqueDirNames[uniqueDirNr - 1] = currDirName;
|
||||
}
|
||||
|
||||
makeMirroredDestDirsWithSameSrcDirMode(uniqueDirNames, uniqueDirNr, outDirName);
|
||||
|
||||
free(uniqueDirNames);
|
||||
}
|
||||
|
||||
static void
|
||||
makeMirroredDestDirs(char** srcFileNames, unsigned nbFile, const char* outDirName)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (i = 0; i < nbFile; ++i)
|
||||
convertPathnameToDirName(srcFileNames[i]);
|
||||
makeUniqueMirroredDestDirs(srcFileNames, nbFile, outDirName);
|
||||
}
|
||||
|
||||
void UTIL_mirrorSourceFilesDirectories(const char** inFileNames, unsigned int nbFile, const char* outDirName)
|
||||
{
|
||||
unsigned int i = 0, validFilenamesNr = 0;
|
||||
char** srcFileNames = (char **) malloc(nbFile * sizeof (char *));
|
||||
CONTROL(srcFileNames != NULL);
|
||||
|
||||
/* check input filenames is valid */
|
||||
for (i = 0; i < nbFile; ++i) {
|
||||
if (isFileNameValidForMirroredOutput(inFileNames[i])) {
|
||||
char* fname = STRDUP(inFileNames[i]);
|
||||
CONTROL(fname != NULL);
|
||||
srcFileNames[validFilenamesNr++] = fname;
|
||||
}
|
||||
}
|
||||
|
||||
if (validFilenamesNr > 0) {
|
||||
makeDir(outDirName, DIR_DEFAULT_MODE);
|
||||
makeMirroredDestDirs(srcFileNames, validFilenamesNr, outDirName);
|
||||
}
|
||||
|
||||
for (i = 0; i < validFilenamesNr; i++)
|
||||
free(srcFileNames[i]);
|
||||
free(srcFileNames);
|
||||
}
|
||||
|
||||
FileNamesTable*
|
||||
UTIL_createExpandedFNT(const char** inputNames, size_t nbIfns, int followLinks)
|
||||
|
||||
@@ -104,6 +104,14 @@ extern int g_utilDisplayLevel;
|
||||
typedef struct stat stat_t;
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__) || defined (__MSVCRT__) /* windows support */
|
||||
#define PATH_SEP '\\'
|
||||
#define STRDUP(s) _strdup(s)
|
||||
#else
|
||||
#define PATH_SEP '/'
|
||||
#include <libgen.h>
|
||||
#define STRDUP(s) strdup(s)
|
||||
#endif
|
||||
|
||||
int UTIL_fileExist(const char* filename);
|
||||
int UTIL_isRegularFile(const char* infilename);
|
||||
@@ -118,9 +126,13 @@ U64 UTIL_getFileSize(const char* infilename);
|
||||
U64 UTIL_getTotalFileSize(const char* const * fileNamesTable, unsigned nbFiles);
|
||||
int UTIL_getFileStat(const char* infilename, stat_t* statbuf);
|
||||
int UTIL_setFileStat(const char* filename, stat_t* statbuf);
|
||||
int UTIL_getDirectoryStat(const char* infilename, stat_t* statbuf);
|
||||
int UTIL_chmod(char const* filename, mode_t permissions); /*< like chmod, but avoid changing permission of /dev/null */
|
||||
int UTIL_compareStr(const void *p1, const void *p2);
|
||||
const char* UTIL_getFileExtension(const char* infilename);
|
||||
void UTIL_mirrorSourceFilesDirectories(const char** fileNamesTable, unsigned int nbFiles, const char *outDirName);
|
||||
char* UTIL_createMirroredDestDirName(const char* srcFileName, const char* outDirRootName);
|
||||
|
||||
|
||||
|
||||
/*-****************************************
|
||||
@@ -207,6 +219,7 @@ void UTIL_refFilename(FileNamesTable* fnt, const char* filename);
|
||||
# define UTIL_HAS_CREATEFILELIST
|
||||
#elif defined(__linux__) || (PLATFORM_POSIX_VERSION >= 200112L) /* opendir, readdir require POSIX.1-2001 */
|
||||
# define UTIL_HAS_CREATEFILELIST
|
||||
# define UTIL_HAS_MIRRORFILELIST
|
||||
#else
|
||||
/* do not define UTIL_HAS_CREATEFILELIST */
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ Note: cannot use both this and \-D together Note: \fB\-\-long\fR mode will be au
|
||||
This is also used during compression when using with \-\-patch\-from=\. In this case, this parameter overrides that maximum size allowed for a dictionary\. (128 MB)\.
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
\fB\-T#\fR, \fB\-\-threads=#\fR: Compress using \fB#\fR working 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==200\. This modifier does nothing if \fBzstd\fR is compiled without multithread support\.
|
||||
\fB\-T#\fR, \fB\-\-threads=#\fR: Compress using \fB#\fR working 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_NBWORKERS_MAX==200\. This modifier does nothing if \fBzstd\fR is compiled without multithread support\.
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
\fB\-\-single\-thread\fR: Does not spawn a thread for compression, use a single thread for both I/O and compression\. In this mode, compression is serialized with I/O, which is slightly slower\. (This is different from \fB\-T1\fR, which spawns 1 compression thread in parallel of I/O)\. This mode is the only one available when multithread support is disabled\. Single\-thread mode features lower memory usage\. Final compressed result is slightly different from \fB\-T1\fR\.
|
||||
|
||||
+15
-5
@@ -129,12 +129,12 @@ the last one takes effect.
|
||||
|
||||
Note: cannot use both this and -D together
|
||||
Note: `--long` mode will be automatically activated if chainLog < fileLog
|
||||
(fileLog being the windowLog requried to cover the whole file). You
|
||||
(fileLog being the windowLog required to cover the whole file). You
|
||||
can also manually force it.
|
||||
Node: for all levels, you can use --patch-from in --single-thread mode
|
||||
to improve compression ratio at the cost of speed
|
||||
Note: for level 19, you can get increased compression ratio at the cost
|
||||
of speed by specifying `--zstd=targetLength=` to be something large
|
||||
Note: for level 19, you can get increased compression ratio at the cost
|
||||
of speed by specifying `--zstd=targetLength=` to be something large
|
||||
(i.e 4096), and by setting a large `--zstd=chainLog=`
|
||||
* `-M#`, `--memory=#`:
|
||||
Set a memory usage limit. By default, Zstandard uses 128 MB for decompression
|
||||
@@ -147,7 +147,7 @@ the last one takes effect.
|
||||
* `-T#`, `--threads=#`:
|
||||
Compress using `#` working threads (default: 1).
|
||||
If `#` 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==200.
|
||||
In all cases, the nb of threads is capped to ZSTDMT_NBWORKERS_MAX==200.
|
||||
This modifier does nothing if `zstd` is compiled without multithread support.
|
||||
* `--single-thread`:
|
||||
Does not spawn a thread for compression, use a single thread for both I/O and compression.
|
||||
@@ -208,7 +208,7 @@ the last one takes effect.
|
||||
This setting overrides default and can force sparse mode over stdout.
|
||||
* `--[no-]content-size`:
|
||||
enable / disable whether or not the original size of the file is placed in
|
||||
the header of the compressed file. The default option is
|
||||
the header of the compressed file. The default option is
|
||||
--content-size (meaning that the original size will be placed in the header).
|
||||
* `--rm`:
|
||||
remove source file(s) after successful compression or decompression
|
||||
@@ -227,6 +227,15 @@ the last one takes effect.
|
||||
if multiple files, from different directories, end up having the same name.
|
||||
Collision resolution ensures first file with a given name will be present in `dir`,
|
||||
while in combination with `-f`, the last file will be present instead.
|
||||
* `--output-dir-mirror[=dir]`:
|
||||
similar to `--output-dir-flat`, the output files are stored underneath target
|
||||
`dir` directory, but this option will preserve input directories structure in output `dir`.
|
||||
|
||||
If the input directory has "..", the files in this directory will be ignored. If
|
||||
the input directory is absolute directory (i.e. "/var/tmp/abc"), it will be
|
||||
stored into the "output-dir/var/tmp/abc".
|
||||
If there is multiple input files or directories, the collision resolution will be same as
|
||||
`--output-dir-flat`.
|
||||
* `--format=FORMAT`:
|
||||
compress and decompress in other formats. If compiled with
|
||||
support, zstd can compress to or decompress from other compression algorithm
|
||||
@@ -238,6 +247,7 @@ the last one takes effect.
|
||||
display version number and exit.
|
||||
Advanced : `-vV` also displays supported formats.
|
||||
`-vvV` also displays POSIX support.
|
||||
`-q` will only display the version number, suitable for machine reading.
|
||||
* `-v`, `--verbose`:
|
||||
verbose mode
|
||||
* `--show-default-cparams`:
|
||||
|
||||
+24
-2
@@ -150,6 +150,10 @@ static void usage_advanced(const char* programName)
|
||||
DISPLAYOUT( "--output-dir-flat=DIR : all resulting files are stored into DIR \n");
|
||||
#endif
|
||||
|
||||
#ifdef UTIL_HAS_MIRRORFILELIST
|
||||
DISPLAYOUT( "--output-dir-mirror==DIR : all resulting files are stored into DIR in the original directory structure \n");
|
||||
#endif
|
||||
|
||||
DISPLAYOUT( "-- : All arguments after \"--\" are treated as files \n");
|
||||
|
||||
#ifndef ZSTD_NOCOMPRESS
|
||||
@@ -544,6 +548,11 @@ static unsigned parseCompressionParameters(const char* stringPtr, ZSTD_compressi
|
||||
|
||||
static void printVersion(void)
|
||||
{
|
||||
if (g_displayLevel < DISPLAY_LEVEL_DEFAULT) {
|
||||
DISPLAYOUT("%s\n", ZSTD_VERSION_STRING);
|
||||
return;
|
||||
}
|
||||
|
||||
DISPLAYOUT(WELCOME_MESSAGE);
|
||||
if (g_displayLevel >= 3) {
|
||||
/* format support */
|
||||
@@ -640,6 +649,7 @@ int main(int const argCount, const char* argv[])
|
||||
rsyncable = 0,
|
||||
nextArgumentIsOutFileName = 0,
|
||||
nextArgumentIsOutDirName = 0,
|
||||
nextArgumentIsMirroredOutDirName = 0,
|
||||
nextArgumentIsMaxDict = 0,
|
||||
nextArgumentIsDictID = 0,
|
||||
nextArgumentsAreFiles = 0,
|
||||
@@ -667,6 +677,7 @@ int main(int const argCount, const char* argv[])
|
||||
const char* programName = argv[0];
|
||||
const char* outFileName = NULL;
|
||||
const char* outDirName = NULL;
|
||||
const char* outMirroredDirName = NULL;
|
||||
const char* dictFileName = NULL;
|
||||
const char* patchFromDictFileName = NULL;
|
||||
const char* suffix = ZSTD_EXTENSION;
|
||||
@@ -763,6 +774,9 @@ int main(int const argCount, const char* argv[])
|
||||
if (!strcmp(argument, "--rm")) { FIO_setRemoveSrcFile(prefs, 1); continue; }
|
||||
if (!strcmp(argument, "--priority=rt")) { setRealTimePrio = 1; continue; }
|
||||
if (!strcmp(argument, "--output-dir-flat")) {nextArgumentIsOutDirName=1; lastCommand=1; continue; }
|
||||
#ifdef UTIL_HAS_MIRRORFILELIST
|
||||
if (!strcmp(argument, "--output-dir-mirror")) {nextArgumentIsMirroredOutDirName=1; lastCommand=1; continue; }
|
||||
#endif
|
||||
if (!strcmp(argument, "--show-default-cparams")) { showDefaultCParams = 1; continue; }
|
||||
if (!strcmp(argument, "--content-size")) { contentSize = 1; continue; }
|
||||
if (!strcmp(argument, "--no-content-size")) { contentSize = 0; continue; }
|
||||
@@ -833,6 +847,7 @@ int main(int const argCount, const char* argv[])
|
||||
if (longCommandWArg(&argument, "--target-compressed-block-size=")) { targetCBlockSize = readSizeTFromChar(&argument); continue; }
|
||||
if (longCommandWArg(&argument, "--size-hint=")) { srcSizeHint = readSizeTFromChar(&argument); continue; }
|
||||
if (longCommandWArg(&argument, "--output-dir-flat=")) { outDirName = argument; continue; }
|
||||
if (longCommandWArg(&argument, "--output-dir-mirror=")) { outMirroredDirName = argument; continue; }
|
||||
if (longCommandWArg(&argument, "--patch-from=")) { patchFromDictFileName = argument; continue; }
|
||||
if (longCommandWArg(&argument, "--long")) {
|
||||
unsigned ldmWindowLog = 0;
|
||||
@@ -1061,6 +1076,13 @@ int main(int const argCount, const char* argv[])
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nextArgumentIsMirroredOutDirName) {
|
||||
nextArgumentIsMirroredOutDirName = 0;
|
||||
lastCommand = 0;
|
||||
outMirroredDirName = argument;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* none of the above : add filename to list */
|
||||
UTIL_refFilename(filenames, argument);
|
||||
}
|
||||
@@ -1325,7 +1347,7 @@ int main(int const argCount, const char* argv[])
|
||||
if ((filenames->tableSize==1) && outFileName)
|
||||
operationResult = FIO_compressFilename(prefs, outFileName, filenames->fileNames[0], dictFileName, cLevel, compressionParams);
|
||||
else
|
||||
operationResult = FIO_compressMultipleFilenames(prefs, filenames->fileNames, (unsigned)filenames->tableSize, outDirName, outFileName, suffix, dictFileName, cLevel, compressionParams);
|
||||
operationResult = FIO_compressMultipleFilenames(prefs, filenames->fileNames, (unsigned)filenames->tableSize, outMirroredDirName, outDirName, outFileName, suffix, dictFileName, cLevel, compressionParams);
|
||||
#else
|
||||
(void)contentSize; (void)suffix; (void)adapt; (void)rsyncable; (void)ultra; (void)cLevel; (void)ldmFlag; (void)literalCompressionMode; (void)targetCBlockSize; (void)streamSrcSize; (void)srcSizeHint; (void)ZSTD_strategyMap; /* not used when ZSTD_NOCOMPRESS set */
|
||||
DISPLAY("Compression not supported \n");
|
||||
@@ -1335,7 +1357,7 @@ int main(int const argCount, const char* argv[])
|
||||
if (filenames->tableSize == 1 && outFileName) {
|
||||
operationResult = FIO_decompressFilename(prefs, outFileName, filenames->fileNames[0], dictFileName);
|
||||
} else {
|
||||
operationResult = FIO_decompressMultipleFilenames(prefs, filenames->fileNames, (unsigned)filenames->tableSize, outDirName, outFileName, dictFileName);
|
||||
operationResult = FIO_decompressMultipleFilenames(prefs, filenames->fileNames, (unsigned)filenames->tableSize, outMirroredDirName, outDirName, outFileName, dictFileName);
|
||||
}
|
||||
#else
|
||||
DISPLAY("Decompression not supported \n");
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?><VAST version="2.0"><Ad id="43C53990160C658B"><Wrapper><AdSystem version="1.0">ads60.vertamedia.com</AdSystem><VASTAdTagURI>http://ads60.vertamedia.com/ops/43C53990160C658B/46991</VASTAdTagURI><Impression><![CDATA[http://ads60.vertamedia.com/i/?x=1&adId=43C53990160C658B&aid=46991&cmpId=13765&fi=24929&advId=13177&pubId=28786&sid=0&width=300&height=250&domain=m.gazetaexpress.com]]></Impression><Creatives><Creative><Linear><TrackingEvents><Tracking event="start">http://ads60.vertamedia.com/ve/43C53990160C658B/53</Tracking><Tracking event="midpoint">http://ads60.vertamedia.com/ve/43C53990160C658B/54</Tracking><Tracking event="firstQuartile">http://ads60.vertamedia.com/ve/43C53990160C658B/55</Tracking><Tracking event="thirdQuartile">http://ads60.vertamedia.com/ve/43C53990160C658B/56</Tracking><Tracking event="complete">http://ads60.vertamedia.com/ve/43C53990160C658B/57</Tracking><Tracking event="skip">http://ads60.vertamedia.com/ve/43C53990160C658B/66</Tracking></TrackingEvents><VideoClicks><ClickTracking>http://ads60.vertamedia.com/ve/43C53990160C658B/71</ClickTracking></VideoClicks></Linear></Creative></Creatives></Wrapper></Ad></VAST>
|
||||
Binary file not shown.
+63
-10
@@ -8,22 +8,22 @@ die() {
|
||||
}
|
||||
|
||||
datagen() {
|
||||
"$DATAGEN_BIN" $@
|
||||
"$DATAGEN_BIN" "$@"
|
||||
}
|
||||
|
||||
zstd() {
|
||||
if [ -z "$EXEC_PREFIX" ]; then
|
||||
"$ZSTD_BIN" $@
|
||||
"$ZSTD_BIN" "$@"
|
||||
else
|
||||
"$EXEC_PREFIX" "$ZSTD_BIN" $@
|
||||
"$EXEC_PREFIX" "$ZSTD_BIN" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
sudoZstd() {
|
||||
if [ -z "$EXEC_PREFIX" ]; then
|
||||
sudo "$ZSTD_BIN" $@
|
||||
sudo "$ZSTD_BIN" "$@"
|
||||
else
|
||||
sudo "$EXEC_PREFIX" "$ZSTD_BIN" $@
|
||||
sudo "$EXEC_PREFIX" "$ZSTD_BIN" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -78,6 +78,11 @@ println() {
|
||||
printf '%b\n' "${*}"
|
||||
}
|
||||
|
||||
if [ -z "${size}" ]; then
|
||||
size=
|
||||
else
|
||||
size=${size}
|
||||
fi
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
|
||||
PRGDIR="$SCRIPT_DIR/../programs"
|
||||
@@ -123,10 +128,25 @@ case "$UNAME" in
|
||||
SunOS) DIFF="gdiff" ;;
|
||||
esac
|
||||
|
||||
println "\nStarting playTests.sh isWindows=$isWindows EXE_PREFIX='$EXE_PREFIX' ZSTD_BIN='$ZSTD_BIN' DATAGEN_BIN='$DATAGEN_BIN'"
|
||||
|
||||
[ -n "$ZSTD_BIN" ] || die "\$ZSTD_BIN variable must be defined!"
|
||||
[ -n "$DATAGEN_BIN" ] || die "\$DATAGEN_BIN variable must be defined!"
|
||||
# check if ZSTD_BIN is defined. if not, use the default value
|
||||
if [ -z "${ZSTD_BIN}" ]; then
|
||||
println "\nZSTD_BIN is not set. Using the default value..."
|
||||
ZSTD_BIN="$PRGDIR/zstd"
|
||||
fi
|
||||
|
||||
# check if DATAGEN_BIN is defined. if not, use the default value
|
||||
if [ -z "${DATAGEN_BIN}" ]; then
|
||||
println "\nDATAGEN_BIN is not set. Using the default value..."
|
||||
DATAGEN_BIN="$TESTDIR/datagen"
|
||||
fi
|
||||
|
||||
ZSTD_BIN="$EXE_PREFIX$ZSTD_BIN"
|
||||
|
||||
# assertions
|
||||
[ -n "$ZSTD_BIN" ] || die "zstd not found at $ZSTD_BIN! \n Please define ZSTD_BIN pointing to the zstd binary. You might also consider rebuilding zstd follwing the instructions in README.md"
|
||||
[ -n "$DATAGEN_BIN" ] || die "datagen not found at $DATAGEN_BIN! \n Please define DATAGEN_BIN pointing to the datagen binary. You might also consider rebuilding zstd tests following the instructions in README.md. "
|
||||
println "\nStarting playTests.sh isWindows=$isWindows EXE_PREFIX='$EXE_PREFIX' ZSTD_BIN='$ZSTD_BIN' DATAGEN_BIN='$DATAGEN_BIN'"
|
||||
|
||||
if echo hello | zstd -v -T2 2>&1 > $INTOVOID | grep -q 'multi-threading is disabled'
|
||||
then
|
||||
@@ -425,6 +445,31 @@ test -f tmpOutDirDecomp/tmp2
|
||||
test -f tmpOutDirDecomp/tmp1
|
||||
rm -rf tmp*
|
||||
|
||||
if [ "$isWindows" = false ] ; then
|
||||
println "\n===> compress multiple files into an output directory and mirror input folder, --output-dir-mirror"
|
||||
println "test --output-dir-mirror" > tmp1
|
||||
mkdir -p tmpInputTestDir/we/must/go/deeper
|
||||
println cool > tmpInputTestDir/we/must/go/deeper/tmp2
|
||||
zstd tmp1 -r tmpInputTestDir --output-dir-mirror tmpOutDir
|
||||
test -f tmpOutDir/tmp1.zst
|
||||
test -f tmpOutDir/tmpInputTestDir/we/must/go/deeper/tmp2.zst
|
||||
|
||||
println "test: compress input dir will be ignored if it has '..'"
|
||||
zstd -r tmpInputTestDir/we/must/../must --output-dir-mirror non-exist && die "input cannot contain '..'"
|
||||
test ! -d non-exist
|
||||
|
||||
println "test : decompress multiple files into an output directory, --output-dir-mirror"
|
||||
zstd tmpOutDir -r -d --output-dir-mirror tmpOutDirDecomp
|
||||
test -f tmpOutDirDecomp/tmpOutDir/tmp1
|
||||
test -f tmpOutDirDecomp/tmpOutDir/tmpInputTestDir/we/must/go/deeper/tmp2
|
||||
|
||||
println "test: decompress input dir will be ignored if it has '..'"
|
||||
zstd -r tmpOutDir/tmpInputTestDir/we/must/../must --output-dir-mirror non-exist && die "input cannot contain '..'"
|
||||
test ! -d non-exist
|
||||
|
||||
rm -rf tmp*
|
||||
fi
|
||||
|
||||
|
||||
println "test : compress multiple files reading them from a file, --filelist=FILE"
|
||||
println "Hello world!, file1" > tmp1
|
||||
@@ -873,8 +918,9 @@ datagen | zstd -c | zstd -t
|
||||
|
||||
println "\n===> golden files tests "
|
||||
|
||||
zstd -t -r "$TESTDIR/golden-compression"
|
||||
zstd -t -r "$TESTDIR/golden-decompression"
|
||||
zstd -c -r "$TESTDIR/golden-compression" | zstd -t
|
||||
zstd -D "$TESTDIR/golden-dictionaries/http-dict-missing-symbols" "$TESTDIR/golden-compression/http" -c | zstd -D "$TESTDIR/golden-dictionaries/http-dict-missing-symbols" -t
|
||||
|
||||
|
||||
println "\n===> benchmark mode tests "
|
||||
@@ -1280,7 +1326,14 @@ println "\n===> patch-from long mode trigger larger file test"
|
||||
|
||||
datagen -g5000000 > tmp_dict
|
||||
datagen -g5000000 > tmp_patch
|
||||
zstd -15 --patch-from=tmp_dict tmp_patch 2>&1 | grep "long mode automaticaly triggered"
|
||||
zstd -15 --patch-from=tmp_dict tmp_patch 2>&1 | grep "long mode automatically triggered"
|
||||
rm -rf tmp*
|
||||
|
||||
println "\n===> patch-from --stream-size test"
|
||||
datagen -g1000 -P50 > tmp_dict
|
||||
datagen -g1000 -P10 > tmp_patch
|
||||
cat tmp_patch | zstd -f --patch-from=tmp_dict -c -o tmp_patch_diff && die
|
||||
cat tmp_patch | zstd -f --patch-from=tmp_dict --stream-size=1000 -c -o tmp_patch_diff
|
||||
rm -rf tmp*
|
||||
|
||||
println "\n===> large files tests "
|
||||
|
||||
Reference in New Issue
Block a user