├── .circleci └── config.yml ├── .github └── ISSUE_TEMPLATE ├── LICENSE ├── README.md ├── ZSTD_LICENSE ├── allocations.h ├── bits.h ├── bitstream.h ├── clevels.h ├── compiler.h ├── cover.c ├── cover.h ├── cpu.h ├── debug.c ├── debug.h ├── divsufsort.c ├── divsufsort.h ├── entropy_common.c ├── error_private.c ├── error_private.h ├── errors.go ├── errors_test.go ├── external_zstd.go ├── fastcover.c ├── fse.h ├── fse_compress.c ├── fse_decompress.c ├── go.mod ├── helpers_test.go ├── hist.c ├── hist.h ├── huf.h ├── huf_compress.c ├── huf_decompress.c ├── huf_decompress_amd64.S ├── mem.h ├── pool.c ├── pool.h ├── portability_macros.h ├── threading.c ├── threading.h ├── tools ├── flatten_imports.py └── insert_libzstd_ifdefs.py ├── travis_test_32.sh ├── update.txt ├── xxhash.c ├── xxhash.h ├── zbuff.h ├── zbuff_common.c ├── zbuff_compress.c ├── zbuff_decompress.c ├── zdict.c ├── zdict.h ├── zstd.go ├── zstd.h ├── zstd_bulk.go ├── zstd_bullk_test.go ├── zstd_common.c ├── zstd_compress.c ├── zstd_compress_internal.h ├── zstd_compress_literals.c ├── zstd_compress_literals.h ├── zstd_compress_sequences.c ├── zstd_compress_sequences.h ├── zstd_compress_superblock.c ├── zstd_compress_superblock.h ├── zstd_ctx.go ├── zstd_ctx_test.go ├── zstd_cwksp.h ├── zstd_ddict.c ├── zstd_ddict.h ├── zstd_decompress.c ├── zstd_decompress_block.c ├── zstd_decompress_block.h ├── zstd_decompress_internal.h ├── zstd_deps.h ├── zstd_double_fast.c ├── zstd_double_fast.h ├── zstd_errors.h ├── zstd_fast.c ├── zstd_fast.h ├── zstd_internal.h ├── zstd_lazy.c ├── zstd_lazy.h ├── zstd_ldm.c ├── zstd_ldm.h ├── zstd_ldm_geartab.h ├── zstd_legacy.h ├── zstd_opt.c ├── zstd_opt.h ├── zstd_preSplit.c ├── zstd_preSplit.h ├── zstd_small_stream_test.go ├── zstd_stream.go ├── zstd_stream_test.go ├── zstd_test.go ├── zstd_trace.h ├── zstd_v01.c ├── zstd_v01.h ├── zstd_v02.c ├── zstd_v02.h ├── zstd_v03.c ├── zstd_v03.h ├── zstd_v04.c ├── zstd_v04.h ├── zstd_v05.c ├── zstd_v05.h ├── zstd_v06.c ├── zstd_v06.h ├── zstd_v07.c ├── zstd_v07.h ├── zstdmt_compress.c └── zstdmt_compress.h /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | jobs: 4 | "golang-1.19": 5 | docker: 6 | - image: cimg/go:1.19 7 | steps: 8 | - checkout 9 | - run: 'wget https://github.com/DataDog/zstd/files/2246767/mr.zip' 10 | - run: 'unzip mr.zip' 11 | - run: 'go build' 12 | - run: 'PAYLOAD=`pwd`/mr go test -v' 13 | - run: 'PAYLOAD=`pwd`/mr go test -bench .' 14 | "golang-1.19-external-libzstd": 15 | docker: 16 | - image: cimg/go:1.19 17 | steps: 18 | - checkout 19 | - run: 'sudo apt update' 20 | - run: 'sudo apt install libzstd-dev' 21 | - run: 'wget https://github.com/DataDog/zstd/files/2246767/mr.zip' 22 | - run: 'unzip mr.zip' 23 | - run: 'go build' 24 | - run: 'PAYLOAD=`pwd`/mr go test -v' 25 | - run: 'PAYLOAD=`pwd`/mr go test -bench .' 26 | "golang-1.20": 27 | docker: 28 | - image: cimg/go:1.20 29 | steps: 30 | - checkout 31 | - run: 'wget https://github.com/DataDog/zstd/files/2246767/mr.zip' 32 | - run: 'unzip mr.zip' 33 | - run: 'go build' 34 | - run: 'PAYLOAD=`pwd`/mr go test -v' 35 | - run: 'PAYLOAD=`pwd`/mr go test -bench .' 36 | "golang-1.20-external-libzstd": 37 | docker: 38 | - image: cimg/go:1.20 39 | steps: 40 | - checkout 41 | - run: 'sudo apt update' 42 | - run: 'sudo apt install libzstd-dev' 43 | - run: 'wget https://github.com/DataDog/zstd/files/2246767/mr.zip' 44 | - run: 'unzip mr.zip' 45 | - run: 'go build' 46 | - run: 'PAYLOAD=`pwd`/mr go test -v' 47 | - run: 'PAYLOAD=`pwd`/mr go test -bench .' 48 | "golang-efence": 49 | resource_class: xlarge 50 | docker: 51 | - image: cimg/go:1.20 52 | steps: 53 | - checkout 54 | - run: 'wget https://github.com/DataDog/zstd/files/2246767/mr.zip' 55 | - run: 'unzip mr.zip' 56 | - run: 'go build' 57 | - run: 'PAYLOAD=`pwd`/mr GODEBUG=efence=1 go test -v' 58 | "golang-efence-external-libzstd": 59 | resource_class: xlarge 60 | docker: 61 | - image: cimg/go:1.20 62 | steps: 63 | - checkout 64 | - run: 'sudo apt update' 65 | - run: 'sudo apt install libzstd-dev' 66 | - run: 'wget https://github.com/DataDog/zstd/files/2246767/mr.zip' 67 | - run: 'unzip mr.zip' 68 | - run: 'go build -tags external_libzstd' 69 | - run: 'PAYLOAD=`pwd`/mr GODEBUG=efence=1 go test -tags external_libzstd -v' 70 | "golang-i386": 71 | docker: 72 | - image: 32bit/ubuntu:16.04 73 | steps: 74 | - checkout 75 | - run: 'linux32 --32bit i386 ./travis_test_32.sh' 76 | 77 | workflows: 78 | version: 2 79 | build: 80 | jobs: 81 | - "golang-1.19" 82 | - "golang-1.19-external-libzstd" 83 | - "golang-1.20" 84 | - "golang-1.20-external-libzstd" 85 | - "golang-efence" 86 | - "golang-efence-external-libzstd" 87 | - "golang-i386" 88 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE: -------------------------------------------------------------------------------- 1 | Please answer these questions before submitting your issue. Thanks! 2 | 3 | ### What version of Go are you using (`go version`)? 4 | 5 | 6 | ### What operating system and processor architecture are you using (`go env`)? 7 | 8 | 9 | ### What did you do? 10 | 11 | If possible, provide a recipe for reproducing the error. 12 | If you have issues building, please parse the output of `go build -x` 13 | 14 | 15 | ### What did you expect to see? 16 | 17 | 18 | ### What did you see instead? 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Simplified BSD License 2 | 3 | Copyright (c) 2016, Datadog 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | * Neither the name of the copyright holder nor the names of its contributors 15 | may be used to endorse or promote products derived from this software 16 | without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zstd Go Wrapper 2 | 3 | [![CircleCI](https://circleci.com/gh/DataDog/zstd/tree/1.x.svg?style=svg)](https://circleci.com/gh/DataDog/zstd/tree/1.x) 4 | [![GoDoc](https://godoc.org/github.com/DataDog/zstd?status.svg)](https://godoc.org/github.com/DataDog/zstd) 5 | 6 | 7 | [C Zstd Homepage](https://github.com/facebook/zstd) 8 | 9 | The current headers and C files are from *v1.5.7* (Commit 10 | [f8745da](https://github.com/facebook/zstd/releases/tag/v1.5.7)). 11 | 12 | ## Usage 13 | 14 | There are two main APIs: 15 | 16 | * simple Compress/Decompress 17 | * streaming API (io.Reader/io.Writer) 18 | 19 | The compress/decompress APIs mirror that of lz4, while the streaming API was 20 | designed to be a drop-in replacement for zlib. 21 | 22 | ### Building against an external libzstd 23 | 24 | By default, zstd source code is vendored in this repository and the binding will be built with 25 | the vendored source code bundled. 26 | 27 | If you want to build this binding against an external static or shared libzstd library, you can 28 | use the `external_libzstd` build tag. This will look for the libzstd pkg-config file and extract 29 | build and linking parameters from that pkg-config file. 30 | 31 | Note that it requires at least libzstd 1.4.0. 32 | 33 | ```bash 34 | go build -tags external_libzstd 35 | ``` 36 | 37 | ### Simple `Compress/Decompress` 38 | 39 | 40 | ```go 41 | // Compress compresses the byte array given in src and writes it to dst. 42 | // If you already have a buffer allocated, you can pass it to prevent allocation 43 | // If not, you can pass nil as dst. 44 | // If the buffer is too small, it will be reallocated, resized, and returned by the function 45 | // If dst is nil, this will allocate the worst case size (CompressBound(src)) 46 | Compress(dst, src []byte) ([]byte, error) 47 | ``` 48 | 49 | ```go 50 | // CompressLevel is the same as Compress but you can pass another compression level 51 | CompressLevel(dst, src []byte, level int) ([]byte, error) 52 | ``` 53 | 54 | ```go 55 | // Decompress will decompress your payload into dst. 56 | // If you already have a buffer allocated, you can pass it to prevent allocation 57 | // If not, you can pass nil as dst (allocates a 4*src size as default). 58 | // If the buffer is too small, it will retry 3 times by doubling the dst size 59 | // After max retries, it will switch to the slower stream API to be sure to be able 60 | // to decompress. Currently switches if compression ratio > 4*2**3=32. 61 | Decompress(dst, src []byte) ([]byte, error) 62 | ``` 63 | 64 | ### Stream API 65 | 66 | ```go 67 | // NewWriter creates a new object that can optionally be initialized with 68 | // a precomputed dictionary. If dict is nil, compress without a dictionary. 69 | // The dictionary array should not be changed during the use of this object. 70 | // You MUST CALL Close() to write the last bytes of a zstd stream and free C objects. 71 | NewWriter(w io.Writer) *Writer 72 | NewWriterLevel(w io.Writer, level int) *Writer 73 | NewWriterLevelDict(w io.Writer, level int, dict []byte) *Writer 74 | 75 | // Write compresses the input data and write it to the underlying writer 76 | (w *Writer) Write(p []byte) (int, error) 77 | 78 | // Flush writes any unwritten data to the underlying writer 79 | (w *Writer) Flush() error 80 | 81 | // Close flushes the buffer and frees C zstd objects 82 | (w *Writer) Close() error 83 | ``` 84 | 85 | ```go 86 | // NewReader returns a new io.ReadCloser that will decompress data from the 87 | // underlying reader. If a dictionary is provided to NewReaderDict, it must 88 | // not be modified until Close is called. It is the caller's responsibility 89 | // to call Close, which frees up C objects. 90 | NewReader(r io.Reader) io.ReadCloser 91 | NewReaderDict(r io.Reader, dict []byte) io.ReadCloser 92 | ``` 93 | 94 | ### Benchmarks (benchmarked with v0.5.0) 95 | 96 | The author of Zstd also wrote lz4. Zstd is intended to occupy a speed/ratio 97 | level similar to what zlib currently provides. In our tests, the can always 98 | be made to be better than zlib by chosing an appropriate level while still 99 | keeping compression and decompression time faster than zlib. 100 | 101 | You can run the benchmarks against your own payloads by using the Go benchmarks tool. 102 | Just export your payload filepath as the `PAYLOAD` environment variable and run the benchmarks: 103 | 104 | ```go 105 | go test -bench . 106 | ``` 107 | 108 | Compression of a 7Mb pdf zstd (this wrapper) vs [czlib](https://github.com/DataDog/czlib): 109 | ``` 110 | BenchmarkCompression 5 221056624 ns/op 67.34 MB/s 111 | BenchmarkDecompression 100 18370416 ns/op 810.32 MB/s 112 | 113 | BenchmarkFzlibCompress 2 610156603 ns/op 24.40 MB/s 114 | BenchmarkFzlibDecompress 20 81195246 ns/op 183.33 MB/s 115 | ``` 116 | 117 | Ratio is also better by a margin of ~20%. 118 | Compression speed is always better than zlib on all the payloads we tested; 119 | However, [czlib](https://github.com/DataDog/czlib) has optimisations that make it 120 | faster at decompressiong small payloads: 121 | 122 | ``` 123 | Testing with size: 11... czlib: 8.97 MB/s, zstd: 3.26 MB/s 124 | Testing with size: 27... czlib: 23.3 MB/s, zstd: 8.22 MB/s 125 | Testing with size: 62... czlib: 31.6 MB/s, zstd: 19.49 MB/s 126 | Testing with size: 141... czlib: 74.54 MB/s, zstd: 42.55 MB/s 127 | Testing with size: 323... czlib: 155.14 MB/s, zstd: 99.39 MB/s 128 | Testing with size: 739... czlib: 235.9 MB/s, zstd: 216.45 MB/s 129 | Testing with size: 1689... czlib: 116.45 MB/s, zstd: 345.64 MB/s 130 | Testing with size: 3858... czlib: 176.39 MB/s, zstd: 617.56 MB/s 131 | Testing with size: 8811... czlib: 254.11 MB/s, zstd: 824.34 MB/s 132 | Testing with size: 20121... czlib: 197.43 MB/s, zstd: 1339.11 MB/s 133 | Testing with size: 45951... czlib: 201.62 MB/s, zstd: 1951.57 MB/s 134 | ``` 135 | 136 | zstd starts to shine with payloads > 1KB 137 | 138 | ### Stability - Current state: STABLE 139 | 140 | The C library seems to be pretty stable and according to the author has been tested and fuzzed. 141 | 142 | For the Go wrapper, the test cover most usual cases and we have succesfully tested it on all staging and prod data. 143 | -------------------------------------------------------------------------------- /ZSTD_LICENSE: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For Zstandard software 4 | 5 | Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name Facebook, nor Meta, nor the names of its contributors may 18 | be used to endorse or promote products derived from this software without 19 | specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /allocations.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | /* This file provides custom allocation primitives 13 | */ 14 | 15 | #define ZSTD_DEPS_NEED_MALLOC 16 | #include "zstd_deps.h" /* ZSTD_malloc, ZSTD_calloc, ZSTD_free, ZSTD_memset */ 17 | 18 | #include "compiler.h" /* MEM_STATIC */ 19 | #define ZSTD_STATIC_LINKING_ONLY 20 | #include "zstd.h" /* ZSTD_customMem */ 21 | 22 | #ifndef ZSTD_ALLOCATIONS_H 23 | #define ZSTD_ALLOCATIONS_H 24 | 25 | /* custom memory allocation functions */ 26 | 27 | MEM_STATIC void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem) 28 | { 29 | if (customMem.customAlloc) 30 | return customMem.customAlloc(customMem.opaque, size); 31 | return ZSTD_malloc(size); 32 | } 33 | 34 | MEM_STATIC void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem) 35 | { 36 | if (customMem.customAlloc) { 37 | /* calloc implemented as malloc+memset; 38 | * not as efficient as calloc, but next best guess for custom malloc */ 39 | void* const ptr = customMem.customAlloc(customMem.opaque, size); 40 | ZSTD_memset(ptr, 0, size); 41 | return ptr; 42 | } 43 | return ZSTD_calloc(1, size); 44 | } 45 | 46 | MEM_STATIC void ZSTD_customFree(void* ptr, ZSTD_customMem customMem) 47 | { 48 | if (ptr!=NULL) { 49 | if (customMem.customFree) 50 | customMem.customFree(customMem.opaque, ptr); 51 | else 52 | ZSTD_free(ptr); 53 | } 54 | } 55 | 56 | #endif /* ZSTD_ALLOCATIONS_H */ 57 | 58 | #endif /* USE_EXTERNAL_ZSTD */ 59 | -------------------------------------------------------------------------------- /bits.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_BITS_H 13 | #define ZSTD_BITS_H 14 | 15 | #include "mem.h" 16 | 17 | MEM_STATIC unsigned ZSTD_countTrailingZeros32_fallback(U32 val) 18 | { 19 | assert(val != 0); 20 | { 21 | static const U32 DeBruijnBytePos[32] = {0, 1, 28, 2, 29, 14, 24, 3, 22 | 30, 22, 20, 15, 25, 17, 4, 8, 23 | 31, 27, 13, 23, 21, 19, 16, 7, 24 | 26, 12, 18, 6, 11, 5, 10, 9}; 25 | return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >> 27]; 26 | } 27 | } 28 | 29 | MEM_STATIC unsigned ZSTD_countTrailingZeros32(U32 val) 30 | { 31 | assert(val != 0); 32 | #if defined(_MSC_VER) 33 | # if STATIC_BMI2 34 | return (unsigned)_tzcnt_u32(val); 35 | # else 36 | if (val != 0) { 37 | unsigned long r; 38 | _BitScanForward(&r, val); 39 | return (unsigned)r; 40 | } else { 41 | __assume(0); /* Should not reach this code path */ 42 | } 43 | # endif 44 | #elif defined(__GNUC__) && (__GNUC__ >= 4) 45 | return (unsigned)__builtin_ctz(val); 46 | #elif defined(__ICCARM__) 47 | return (unsigned)__builtin_ctz(val); 48 | #else 49 | return ZSTD_countTrailingZeros32_fallback(val); 50 | #endif 51 | } 52 | 53 | MEM_STATIC unsigned ZSTD_countLeadingZeros32_fallback(U32 val) 54 | { 55 | assert(val != 0); 56 | { 57 | static const U32 DeBruijnClz[32] = {0, 9, 1, 10, 13, 21, 2, 29, 58 | 11, 14, 16, 18, 22, 25, 3, 30, 59 | 8, 12, 20, 28, 15, 17, 24, 7, 60 | 19, 27, 23, 6, 26, 5, 4, 31}; 61 | val |= val >> 1; 62 | val |= val >> 2; 63 | val |= val >> 4; 64 | val |= val >> 8; 65 | val |= val >> 16; 66 | return 31 - DeBruijnClz[(val * 0x07C4ACDDU) >> 27]; 67 | } 68 | } 69 | 70 | MEM_STATIC unsigned ZSTD_countLeadingZeros32(U32 val) 71 | { 72 | assert(val != 0); 73 | #if defined(_MSC_VER) 74 | # if STATIC_BMI2 75 | return (unsigned)_lzcnt_u32(val); 76 | # else 77 | if (val != 0) { 78 | unsigned long r; 79 | _BitScanReverse(&r, val); 80 | return (unsigned)(31 - r); 81 | } else { 82 | __assume(0); /* Should not reach this code path */ 83 | } 84 | # endif 85 | #elif defined(__GNUC__) && (__GNUC__ >= 4) 86 | return (unsigned)__builtin_clz(val); 87 | #elif defined(__ICCARM__) 88 | return (unsigned)__builtin_clz(val); 89 | #else 90 | return ZSTD_countLeadingZeros32_fallback(val); 91 | #endif 92 | } 93 | 94 | MEM_STATIC unsigned ZSTD_countTrailingZeros64(U64 val) 95 | { 96 | assert(val != 0); 97 | #if defined(_MSC_VER) && defined(_WIN64) 98 | # if STATIC_BMI2 99 | return (unsigned)_tzcnt_u64(val); 100 | # else 101 | if (val != 0) { 102 | unsigned long r; 103 | _BitScanForward64(&r, val); 104 | return (unsigned)r; 105 | } else { 106 | __assume(0); /* Should not reach this code path */ 107 | } 108 | # endif 109 | #elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(__LP64__) 110 | return (unsigned)__builtin_ctzll(val); 111 | #elif defined(__ICCARM__) 112 | return (unsigned)__builtin_ctzll(val); 113 | #else 114 | { 115 | U32 mostSignificantWord = (U32)(val >> 32); 116 | U32 leastSignificantWord = (U32)val; 117 | if (leastSignificantWord == 0) { 118 | return 32 + ZSTD_countTrailingZeros32(mostSignificantWord); 119 | } else { 120 | return ZSTD_countTrailingZeros32(leastSignificantWord); 121 | } 122 | } 123 | #endif 124 | } 125 | 126 | MEM_STATIC unsigned ZSTD_countLeadingZeros64(U64 val) 127 | { 128 | assert(val != 0); 129 | #if defined(_MSC_VER) && defined(_WIN64) 130 | # if STATIC_BMI2 131 | return (unsigned)_lzcnt_u64(val); 132 | # else 133 | if (val != 0) { 134 | unsigned long r; 135 | _BitScanReverse64(&r, val); 136 | return (unsigned)(63 - r); 137 | } else { 138 | __assume(0); /* Should not reach this code path */ 139 | } 140 | # endif 141 | #elif defined(__GNUC__) && (__GNUC__ >= 4) 142 | return (unsigned)(__builtin_clzll(val)); 143 | #elif defined(__ICCARM__) 144 | return (unsigned)(__builtin_clzll(val)); 145 | #else 146 | { 147 | U32 mostSignificantWord = (U32)(val >> 32); 148 | U32 leastSignificantWord = (U32)val; 149 | if (mostSignificantWord == 0) { 150 | return 32 + ZSTD_countLeadingZeros32(leastSignificantWord); 151 | } else { 152 | return ZSTD_countLeadingZeros32(mostSignificantWord); 153 | } 154 | } 155 | #endif 156 | } 157 | 158 | MEM_STATIC unsigned ZSTD_NbCommonBytes(size_t val) 159 | { 160 | if (MEM_isLittleEndian()) { 161 | if (MEM_64bits()) { 162 | return ZSTD_countTrailingZeros64((U64)val) >> 3; 163 | } else { 164 | return ZSTD_countTrailingZeros32((U32)val) >> 3; 165 | } 166 | } else { /* Big Endian CPU */ 167 | if (MEM_64bits()) { 168 | return ZSTD_countLeadingZeros64((U64)val) >> 3; 169 | } else { 170 | return ZSTD_countLeadingZeros32((U32)val) >> 3; 171 | } 172 | } 173 | } 174 | 175 | MEM_STATIC unsigned ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ 176 | { 177 | assert(val != 0); 178 | return 31 - ZSTD_countLeadingZeros32(val); 179 | } 180 | 181 | /* ZSTD_rotateRight_*(): 182 | * Rotates a bitfield to the right by "count" bits. 183 | * https://en.wikipedia.org/w/index.php?title=Circular_shift&oldid=991635599#Implementing_circular_shifts 184 | */ 185 | MEM_STATIC 186 | U64 ZSTD_rotateRight_U64(U64 const value, U32 count) { 187 | assert(count < 64); 188 | count &= 0x3F; /* for fickle pattern recognition */ 189 | return (value >> count) | (U64)(value << ((0U - count) & 0x3F)); 190 | } 191 | 192 | MEM_STATIC 193 | U32 ZSTD_rotateRight_U32(U32 const value, U32 count) { 194 | assert(count < 32); 195 | count &= 0x1F; /* for fickle pattern recognition */ 196 | return (value >> count) | (U32)(value << ((0U - count) & 0x1F)); 197 | } 198 | 199 | MEM_STATIC 200 | U16 ZSTD_rotateRight_U16(U16 const value, U32 count) { 201 | assert(count < 16); 202 | count &= 0x0F; /* for fickle pattern recognition */ 203 | return (value >> count) | (U16)(value << ((0U - count) & 0x0F)); 204 | } 205 | 206 | #endif /* ZSTD_BITS_H */ 207 | 208 | #endif /* USE_EXTERNAL_ZSTD */ 209 | -------------------------------------------------------------------------------- /clevels.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_CLEVELS_H 13 | #define ZSTD_CLEVELS_H 14 | 15 | #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressionParameters */ 16 | #include "zstd.h" 17 | 18 | /*-===== Pre-defined compression levels =====-*/ 19 | 20 | #define ZSTD_MAX_CLEVEL 22 21 | 22 | #ifdef __GNUC__ 23 | __attribute__((__unused__)) 24 | #endif 25 | 26 | static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { 27 | { /* "default" - for any srcSize > 256 KB */ 28 | /* W, C, H, S, L, TL, strat */ 29 | { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ 30 | { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ 31 | { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ 32 | { 21, 16, 17, 1, 5, 0, ZSTD_dfast }, /* level 3 */ 33 | { 21, 18, 18, 1, 5, 0, ZSTD_dfast }, /* level 4 */ 34 | { 21, 18, 19, 3, 5, 2, ZSTD_greedy }, /* level 5 */ 35 | { 21, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6 */ 36 | { 21, 19, 20, 4, 5, 8, ZSTD_lazy }, /* level 7 */ 37 | { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 8 */ 38 | { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ 39 | { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 10 */ 40 | { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 11 */ 41 | { 22, 22, 23, 6, 5, 32, ZSTD_lazy2 }, /* level 12 */ 42 | { 22, 22, 22, 4, 5, 32, ZSTD_btlazy2 }, /* level 13 */ 43 | { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ 44 | { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ 45 | { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */ 46 | { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */ 47 | { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */ 48 | { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */ 49 | { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */ 50 | { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */ 51 | { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */ 52 | }, 53 | { /* for srcSize <= 256 KB */ 54 | /* W, C, H, S, L, T, strat */ 55 | { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 56 | { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ 57 | { 18, 14, 14, 1, 5, 0, ZSTD_dfast }, /* level 2 */ 58 | { 18, 16, 16, 1, 4, 0, ZSTD_dfast }, /* level 3 */ 59 | { 18, 16, 17, 3, 5, 2, ZSTD_greedy }, /* level 4.*/ 60 | { 18, 17, 18, 5, 5, 2, ZSTD_greedy }, /* level 5.*/ 61 | { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ 62 | { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ 63 | { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 64 | { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 65 | { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 66 | { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/ 67 | { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/ 68 | { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */ 69 | { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ 70 | { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/ 71 | { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/ 72 | { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/ 73 | { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/ 74 | { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ 75 | { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/ 76 | { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/ 77 | { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/ 78 | }, 79 | { /* for srcSize <= 128 KB */ 80 | /* W, C, H, S, L, T, strat */ 81 | { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 82 | { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ 83 | { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ 84 | { 17, 15, 16, 2, 5, 0, ZSTD_dfast }, /* level 3 */ 85 | { 17, 17, 17, 2, 4, 0, ZSTD_dfast }, /* level 4 */ 86 | { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ 87 | { 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ 88 | { 17, 16, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ 89 | { 17, 16, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 90 | { 17, 16, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 91 | { 17, 16, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 92 | { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */ 93 | { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */ 94 | { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/ 95 | { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ 96 | { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/ 97 | { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/ 98 | { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/ 99 | { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/ 100 | { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/ 101 | { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/ 102 | { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ 103 | { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/ 104 | }, 105 | { /* for srcSize <= 16 KB */ 106 | /* W, C, H, S, L, T, strat */ 107 | { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 108 | { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ 109 | { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ 110 | { 14, 14, 15, 2, 4, 0, ZSTD_dfast }, /* level 3 */ 111 | { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */ 112 | { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ 113 | { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ 114 | { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ 115 | { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ 116 | { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ 117 | { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ 118 | { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ 119 | { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/ 120 | { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/ 121 | { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/ 122 | { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/ 123 | { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/ 124 | { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/ 125 | { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/ 126 | { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ 127 | { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/ 128 | { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ 129 | { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/ 130 | }, 131 | }; 132 | 133 | 134 | 135 | #endif /* ZSTD_CLEVELS_H */ 136 | 137 | #endif /* USE_EXTERNAL_ZSTD */ 138 | -------------------------------------------------------------------------------- /cover.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZDICT_STATIC_LINKING_ONLY 13 | # define ZDICT_STATIC_LINKING_ONLY 14 | #endif 15 | 16 | #include "threading.h" /* ZSTD_pthread_mutex_t */ 17 | #include "mem.h" /* U32, BYTE */ 18 | #include "zdict.h" 19 | 20 | /** 21 | * COVER_best_t is used for two purposes: 22 | * 1. Synchronizing threads. 23 | * 2. Saving the best parameters and dictionary. 24 | * 25 | * All of the methods except COVER_best_init() are thread safe if zstd is 26 | * compiled with multithreaded support. 27 | */ 28 | typedef struct COVER_best_s { 29 | ZSTD_pthread_mutex_t mutex; 30 | ZSTD_pthread_cond_t cond; 31 | size_t liveJobs; 32 | void *dict; 33 | size_t dictSize; 34 | ZDICT_cover_params_t parameters; 35 | size_t compressedSize; 36 | } COVER_best_t; 37 | 38 | /** 39 | * A segment is a range in the source as well as the score of the segment. 40 | */ 41 | typedef struct { 42 | U32 begin; 43 | U32 end; 44 | U32 score; 45 | } COVER_segment_t; 46 | 47 | /** 48 | *Number of epochs and size of each epoch. 49 | */ 50 | typedef struct { 51 | U32 num; 52 | U32 size; 53 | } COVER_epoch_info_t; 54 | 55 | /** 56 | * Struct used for the dictionary selection function. 57 | */ 58 | typedef struct COVER_dictSelection { 59 | BYTE* dictContent; 60 | size_t dictSize; 61 | size_t totalCompressedSize; 62 | } COVER_dictSelection_t; 63 | 64 | /** 65 | * Computes the number of epochs and the size of each epoch. 66 | * We will make sure that each epoch gets at least 10 * k bytes. 67 | * 68 | * The COVER algorithms divide the data up into epochs of equal size and 69 | * select one segment from each epoch. 70 | * 71 | * @param maxDictSize The maximum allowed dictionary size. 72 | * @param nbDmers The number of dmers we are training on. 73 | * @param k The parameter k (segment size). 74 | * @param passes The target number of passes over the dmer corpus. 75 | * More passes means a better dictionary. 76 | */ 77 | COVER_epoch_info_t COVER_computeEpochs(U32 maxDictSize, U32 nbDmers, 78 | U32 k, U32 passes); 79 | 80 | /** 81 | * Warns the user when their corpus is too small. 82 | */ 83 | void COVER_warnOnSmallCorpus(size_t maxDictSize, size_t nbDmers, int displayLevel); 84 | 85 | /** 86 | * Checks total compressed size of a dictionary 87 | */ 88 | size_t COVER_checkTotalCompressedSize(const ZDICT_cover_params_t parameters, 89 | const size_t *samplesSizes, const BYTE *samples, 90 | size_t *offsets, 91 | size_t nbTrainSamples, size_t nbSamples, 92 | BYTE *const dict, size_t dictBufferCapacity); 93 | 94 | /** 95 | * Returns the sum of the sample sizes. 96 | */ 97 | size_t COVER_sum(const size_t *samplesSizes, unsigned nbSamples) ; 98 | 99 | /** 100 | * Initialize the `COVER_best_t`. 101 | */ 102 | void COVER_best_init(COVER_best_t *best); 103 | 104 | /** 105 | * Wait until liveJobs == 0. 106 | */ 107 | void COVER_best_wait(COVER_best_t *best); 108 | 109 | /** 110 | * Call COVER_best_wait() and then destroy the COVER_best_t. 111 | */ 112 | void COVER_best_destroy(COVER_best_t *best); 113 | 114 | /** 115 | * Called when a thread is about to be launched. 116 | * Increments liveJobs. 117 | */ 118 | void COVER_best_start(COVER_best_t *best); 119 | 120 | /** 121 | * Called when a thread finishes executing, both on error or success. 122 | * Decrements liveJobs and signals any waiting threads if liveJobs == 0. 123 | * If this dictionary is the best so far save it and its parameters. 124 | */ 125 | void COVER_best_finish(COVER_best_t *best, ZDICT_cover_params_t parameters, 126 | COVER_dictSelection_t selection); 127 | /** 128 | * Error function for COVER_selectDict function. Checks if the return 129 | * value is an error. 130 | */ 131 | unsigned COVER_dictSelectionIsError(COVER_dictSelection_t selection); 132 | 133 | /** 134 | * Error function for COVER_selectDict function. Returns a struct where 135 | * return.totalCompressedSize is a ZSTD error. 136 | */ 137 | COVER_dictSelection_t COVER_dictSelectionError(size_t error); 138 | 139 | /** 140 | * Always call after selectDict is called to free up used memory from 141 | * newly created dictionary. 142 | */ 143 | void COVER_dictSelectionFree(COVER_dictSelection_t selection); 144 | 145 | /** 146 | * Called to finalize the dictionary and select one based on whether or not 147 | * the shrink-dict flag was enabled. If enabled the dictionary used is the 148 | * smallest dictionary within a specified regression of the compressed size 149 | * from the largest dictionary. 150 | */ 151 | COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBufferCapacity, 152 | size_t dictContentSize, const BYTE* samplesBuffer, const size_t* samplesSizes, unsigned nbFinalizeSamples, 153 | size_t nbCheckSamples, size_t nbSamples, ZDICT_cover_params_t params, size_t* offsets, size_t totalCompressedSize); 154 | 155 | #endif /* USE_EXTERNAL_ZSTD */ 156 | -------------------------------------------------------------------------------- /cpu.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_COMMON_CPU_H 13 | #define ZSTD_COMMON_CPU_H 14 | 15 | /** 16 | * Implementation taken from folly/CpuId.h 17 | * https://github.com/facebook/folly/blob/master/folly/CpuId.h 18 | */ 19 | 20 | #include "mem.h" 21 | 22 | #ifdef _MSC_VER 23 | #include 24 | #endif 25 | 26 | typedef struct { 27 | U32 f1c; 28 | U32 f1d; 29 | U32 f7b; 30 | U32 f7c; 31 | } ZSTD_cpuid_t; 32 | 33 | MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) { 34 | U32 f1c = 0; 35 | U32 f1d = 0; 36 | U32 f7b = 0; 37 | U32 f7c = 0; 38 | #if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) 39 | #if !defined(_M_X64) || !defined(__clang__) || __clang_major__ >= 16 40 | int reg[4]; 41 | __cpuid((int*)reg, 0); 42 | { 43 | int const n = reg[0]; 44 | if (n >= 1) { 45 | __cpuid((int*)reg, 1); 46 | f1c = (U32)reg[2]; 47 | f1d = (U32)reg[3]; 48 | } 49 | if (n >= 7) { 50 | __cpuidex((int*)reg, 7, 0); 51 | f7b = (U32)reg[1]; 52 | f7c = (U32)reg[2]; 53 | } 54 | } 55 | #else 56 | /* Clang compiler has a bug (fixed in https://reviews.llvm.org/D101338) in 57 | * which the `__cpuid` intrinsic does not save and restore `rbx` as it needs 58 | * to due to being a reserved register. So in that case, do the `cpuid` 59 | * ourselves. Clang supports inline assembly anyway. 60 | */ 61 | U32 n; 62 | __asm__( 63 | "pushq %%rbx\n\t" 64 | "cpuid\n\t" 65 | "popq %%rbx\n\t" 66 | : "=a"(n) 67 | : "a"(0) 68 | : "rcx", "rdx"); 69 | if (n >= 1) { 70 | U32 f1a; 71 | __asm__( 72 | "pushq %%rbx\n\t" 73 | "cpuid\n\t" 74 | "popq %%rbx\n\t" 75 | : "=a"(f1a), "=c"(f1c), "=d"(f1d) 76 | : "a"(1) 77 | :); 78 | } 79 | if (n >= 7) { 80 | __asm__( 81 | "pushq %%rbx\n\t" 82 | "cpuid\n\t" 83 | "movq %%rbx, %%rax\n\t" 84 | "popq %%rbx" 85 | : "=a"(f7b), "=c"(f7c) 86 | : "a"(7), "c"(0) 87 | : "rdx"); 88 | } 89 | #endif 90 | #elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__) 91 | /* The following block like the normal cpuid branch below, but gcc 92 | * reserves ebx for use of its pic register so we must specially 93 | * handle the save and restore to avoid clobbering the register 94 | */ 95 | U32 n; 96 | __asm__( 97 | "pushl %%ebx\n\t" 98 | "cpuid\n\t" 99 | "popl %%ebx\n\t" 100 | : "=a"(n) 101 | : "a"(0) 102 | : "ecx", "edx"); 103 | if (n >= 1) { 104 | U32 f1a; 105 | __asm__( 106 | "pushl %%ebx\n\t" 107 | "cpuid\n\t" 108 | "popl %%ebx\n\t" 109 | : "=a"(f1a), "=c"(f1c), "=d"(f1d) 110 | : "a"(1)); 111 | } 112 | if (n >= 7) { 113 | __asm__( 114 | "pushl %%ebx\n\t" 115 | "cpuid\n\t" 116 | "movl %%ebx, %%eax\n\t" 117 | "popl %%ebx" 118 | : "=a"(f7b), "=c"(f7c) 119 | : "a"(7), "c"(0) 120 | : "edx"); 121 | } 122 | #elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__) 123 | U32 n; 124 | __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx"); 125 | if (n >= 1) { 126 | U32 f1a; 127 | __asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx"); 128 | } 129 | if (n >= 7) { 130 | U32 f7a; 131 | __asm__("cpuid" 132 | : "=a"(f7a), "=b"(f7b), "=c"(f7c) 133 | : "a"(7), "c"(0) 134 | : "edx"); 135 | } 136 | #endif 137 | { 138 | ZSTD_cpuid_t cpuid; 139 | cpuid.f1c = f1c; 140 | cpuid.f1d = f1d; 141 | cpuid.f7b = f7b; 142 | cpuid.f7c = f7c; 143 | return cpuid; 144 | } 145 | } 146 | 147 | #define X(name, r, bit) \ 148 | MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \ 149 | return ((cpuid.r) & (1U << bit)) != 0; \ 150 | } 151 | 152 | /* cpuid(1): Processor Info and Feature Bits. */ 153 | #define C(name, bit) X(name, f1c, bit) 154 | C(sse3, 0) 155 | C(pclmuldq, 1) 156 | C(dtes64, 2) 157 | C(monitor, 3) 158 | C(dscpl, 4) 159 | C(vmx, 5) 160 | C(smx, 6) 161 | C(eist, 7) 162 | C(tm2, 8) 163 | C(ssse3, 9) 164 | C(cnxtid, 10) 165 | C(fma, 12) 166 | C(cx16, 13) 167 | C(xtpr, 14) 168 | C(pdcm, 15) 169 | C(pcid, 17) 170 | C(dca, 18) 171 | C(sse41, 19) 172 | C(sse42, 20) 173 | C(x2apic, 21) 174 | C(movbe, 22) 175 | C(popcnt, 23) 176 | C(tscdeadline, 24) 177 | C(aes, 25) 178 | C(xsave, 26) 179 | C(osxsave, 27) 180 | C(avx, 28) 181 | C(f16c, 29) 182 | C(rdrand, 30) 183 | #undef C 184 | #define D(name, bit) X(name, f1d, bit) 185 | D(fpu, 0) 186 | D(vme, 1) 187 | D(de, 2) 188 | D(pse, 3) 189 | D(tsc, 4) 190 | D(msr, 5) 191 | D(pae, 6) 192 | D(mce, 7) 193 | D(cx8, 8) 194 | D(apic, 9) 195 | D(sep, 11) 196 | D(mtrr, 12) 197 | D(pge, 13) 198 | D(mca, 14) 199 | D(cmov, 15) 200 | D(pat, 16) 201 | D(pse36, 17) 202 | D(psn, 18) 203 | D(clfsh, 19) 204 | D(ds, 21) 205 | D(acpi, 22) 206 | D(mmx, 23) 207 | D(fxsr, 24) 208 | D(sse, 25) 209 | D(sse2, 26) 210 | D(ss, 27) 211 | D(htt, 28) 212 | D(tm, 29) 213 | D(pbe, 31) 214 | #undef D 215 | 216 | /* cpuid(7): Extended Features. */ 217 | #define B(name, bit) X(name, f7b, bit) 218 | B(bmi1, 3) 219 | B(hle, 4) 220 | B(avx2, 5) 221 | B(smep, 7) 222 | B(bmi2, 8) 223 | B(erms, 9) 224 | B(invpcid, 10) 225 | B(rtm, 11) 226 | B(mpx, 14) 227 | B(avx512f, 16) 228 | B(avx512dq, 17) 229 | B(rdseed, 18) 230 | B(adx, 19) 231 | B(smap, 20) 232 | B(avx512ifma, 21) 233 | B(pcommit, 22) 234 | B(clflushopt, 23) 235 | B(clwb, 24) 236 | B(avx512pf, 26) 237 | B(avx512er, 27) 238 | B(avx512cd, 28) 239 | B(sha, 29) 240 | B(avx512bw, 30) 241 | B(avx512vl, 31) 242 | #undef B 243 | #define C(name, bit) X(name, f7c, bit) 244 | C(prefetchwt1, 0) 245 | C(avx512vbmi, 1) 246 | #undef C 247 | 248 | #undef X 249 | 250 | #endif /* ZSTD_COMMON_CPU_H */ 251 | 252 | #endif /* USE_EXTERNAL_ZSTD */ 253 | -------------------------------------------------------------------------------- /debug.c: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* ****************************************************************** 3 | * debug 4 | * Part of FSE library 5 | * Copyright (c) Meta Platforms, Inc. and affiliates. 6 | * 7 | * You can contact the author at : 8 | * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy 9 | * 10 | * This source code is licensed under both the BSD-style license (found in the 11 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 12 | * in the COPYING file in the root directory of this source tree). 13 | * You may select, at your option, one of the above-listed licenses. 14 | ****************************************************************** */ 15 | 16 | 17 | /* 18 | * This module only hosts one global variable 19 | * which can be used to dynamically influence the verbosity of traces, 20 | * such as DEBUGLOG and RAWLOG 21 | */ 22 | 23 | #include "debug.h" 24 | 25 | #if !defined(ZSTD_LINUX_KERNEL) || (DEBUGLEVEL>=2) 26 | /* We only use this when DEBUGLEVEL>=2, but we get -Werror=pedantic errors if a 27 | * translation unit is empty. So remove this from Linux kernel builds, but 28 | * otherwise just leave it in. 29 | */ 30 | int g_debuglevel = DEBUGLEVEL; 31 | #endif 32 | 33 | #endif /* USE_EXTERNAL_ZSTD */ 34 | -------------------------------------------------------------------------------- /debug.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* ****************************************************************** 3 | * debug 4 | * Part of FSE library 5 | * Copyright (c) Meta Platforms, Inc. and affiliates. 6 | * 7 | * You can contact the author at : 8 | * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy 9 | * 10 | * This source code is licensed under both the BSD-style license (found in the 11 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 12 | * in the COPYING file in the root directory of this source tree). 13 | * You may select, at your option, one of the above-listed licenses. 14 | ****************************************************************** */ 15 | 16 | 17 | /* 18 | * The purpose of this header is to enable debug functions. 19 | * They regroup assert(), DEBUGLOG() and RAWLOG() for run-time, 20 | * and DEBUG_STATIC_ASSERT() for compile-time. 21 | * 22 | * By default, DEBUGLEVEL==0, which means run-time debug is disabled. 23 | * 24 | * Level 1 enables assert() only. 25 | * Starting level 2, traces can be generated and pushed to stderr. 26 | * The higher the level, the more verbose the traces. 27 | * 28 | * It's possible to dynamically adjust level using variable g_debug_level, 29 | * which is only declared if DEBUGLEVEL>=2, 30 | * and is a global variable, not multi-thread protected (use with care) 31 | */ 32 | 33 | #ifndef DEBUG_H_12987983217 34 | #define DEBUG_H_12987983217 35 | 36 | 37 | /* static assert is triggered at compile time, leaving no runtime artefact. 38 | * static assert only works with compile-time constants. 39 | * Also, this variant can only be used inside a function. */ 40 | #define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1]) 41 | 42 | 43 | /* DEBUGLEVEL is expected to be defined externally, 44 | * typically through compiler command line. 45 | * Value must be a number. */ 46 | #ifndef DEBUGLEVEL 47 | # define DEBUGLEVEL 0 48 | #endif 49 | 50 | 51 | /* recommended values for DEBUGLEVEL : 52 | * 0 : release mode, no debug, all run-time checks disabled 53 | * 1 : enables assert() only, no display 54 | * 2 : reserved, for currently active debug path 55 | * 3 : events once per object lifetime (CCtx, CDict, etc.) 56 | * 4 : events once per frame 57 | * 5 : events once per block 58 | * 6 : events once per sequence (verbose) 59 | * 7+: events at every position (*very* verbose) 60 | * 61 | * It's generally inconvenient to output traces > 5. 62 | * In which case, it's possible to selectively trigger high verbosity levels 63 | * by modifying g_debug_level. 64 | */ 65 | 66 | #if (DEBUGLEVEL>=1) 67 | # define ZSTD_DEPS_NEED_ASSERT 68 | # include "zstd_deps.h" 69 | #else 70 | # ifndef assert /* assert may be already defined, due to prior #include */ 71 | # define assert(condition) ((void)0) /* disable assert (default) */ 72 | # endif 73 | #endif 74 | 75 | #if (DEBUGLEVEL>=2) 76 | # define ZSTD_DEPS_NEED_IO 77 | # include "zstd_deps.h" 78 | extern int g_debuglevel; /* the variable is only declared, 79 | it actually lives in debug.c, 80 | and is shared by the whole process. 81 | It's not thread-safe. 82 | It's useful when enabling very verbose levels 83 | on selective conditions (such as position in src) */ 84 | 85 | # define RAWLOG(l, ...) \ 86 | do { \ 87 | if (l<=g_debuglevel) { \ 88 | ZSTD_DEBUG_PRINT(__VA_ARGS__); \ 89 | } \ 90 | } while (0) 91 | 92 | #define STRINGIFY(x) #x 93 | #define TOSTRING(x) STRINGIFY(x) 94 | #define LINE_AS_STRING TOSTRING(__LINE__) 95 | 96 | # define DEBUGLOG(l, ...) \ 97 | do { \ 98 | if (l<=g_debuglevel) { \ 99 | ZSTD_DEBUG_PRINT(__FILE__ ":" LINE_AS_STRING ": " __VA_ARGS__); \ 100 | ZSTD_DEBUG_PRINT(" \n"); \ 101 | } \ 102 | } while (0) 103 | #else 104 | # define RAWLOG(l, ...) do { } while (0) /* disabled */ 105 | # define DEBUGLOG(l, ...) do { } while (0) /* disabled */ 106 | #endif 107 | 108 | #endif /* DEBUG_H_12987983217 */ 109 | 110 | #endif /* USE_EXTERNAL_ZSTD */ 111 | -------------------------------------------------------------------------------- /divsufsort.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * divsufsort.h for libdivsufsort-lite 4 | * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person 7 | * obtaining a copy of this software and associated documentation 8 | * files (the "Software"), to deal in the Software without 9 | * restriction, including without limitation the rights to use, 10 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the 12 | * Software is furnished to do so, subject to the following 13 | * conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be 16 | * included in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | * OTHER DEALINGS IN THE SOFTWARE. 26 | */ 27 | 28 | #ifndef _DIVSUFSORT_H 29 | #define _DIVSUFSORT_H 1 30 | 31 | /*- Prototypes -*/ 32 | 33 | /** 34 | * Constructs the suffix array of a given string. 35 | * @param T [0..n-1] The input string. 36 | * @param SA [0..n-1] The output array of suffixes. 37 | * @param n The length of the given string. 38 | * @param openMP enables OpenMP optimization. 39 | * @return 0 if no error occurred, -1 or -2 otherwise. 40 | */ 41 | int 42 | divsufsort(const unsigned char *T, int *SA, int n, int openMP); 43 | 44 | /** 45 | * Constructs the burrows-wheeler transformed string of a given string. 46 | * @param T [0..n-1] The input string. 47 | * @param U [0..n-1] The output string. (can be T) 48 | * @param A [0..n-1] The temporary array. (can be NULL) 49 | * @param n The length of the given string. 50 | * @param num_indexes The length of secondary indexes array. (can be NULL) 51 | * @param indexes The secondary indexes array. (can be NULL) 52 | * @param openMP enables OpenMP optimization. 53 | * @return The primary index if no error occurred, -1 or -2 otherwise. 54 | */ 55 | int 56 | divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * num_indexes, int * indexes, int openMP); 57 | 58 | #endif /* _DIVSUFSORT_H */ 59 | 60 | #endif /* USE_EXTERNAL_ZSTD */ 61 | -------------------------------------------------------------------------------- /error_private.c: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | /* The purpose of this file is to have a single list of error strings embedded in binary */ 13 | 14 | #include "error_private.h" 15 | 16 | const char* ERR_getErrorString(ERR_enum code) 17 | { 18 | #ifdef ZSTD_STRIP_ERROR_STRINGS 19 | (void)code; 20 | return "Error strings stripped"; 21 | #else 22 | static const char* const notErrorCode = "Unspecified error code"; 23 | switch( code ) 24 | { 25 | case PREFIX(no_error): return "No error detected"; 26 | case PREFIX(GENERIC): return "Error (generic)"; 27 | case PREFIX(prefix_unknown): return "Unknown frame descriptor"; 28 | case PREFIX(version_unsupported): return "Version not supported"; 29 | case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; 30 | case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding"; 31 | case PREFIX(corruption_detected): return "Data corruption detected"; 32 | case PREFIX(checksum_wrong): return "Restored data doesn't match checksum"; 33 | case PREFIX(literals_headerWrong): return "Header of Literals' block doesn't respect format specification"; 34 | case PREFIX(parameter_unsupported): return "Unsupported parameter"; 35 | case PREFIX(parameter_combination_unsupported): return "Unsupported combination of parameters"; 36 | case PREFIX(parameter_outOfBound): return "Parameter is out of bound"; 37 | case PREFIX(init_missing): return "Context should be init first"; 38 | case PREFIX(memory_allocation): return "Allocation error : not enough memory"; 39 | case PREFIX(workSpace_tooSmall): return "workSpace buffer is not large enough"; 40 | case PREFIX(stage_wrong): return "Operation not authorized at current processing stage"; 41 | case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; 42 | case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; 43 | case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; 44 | case PREFIX(cannotProduce_uncompressedBlock): return "This mode cannot generate an uncompressed block"; 45 | case PREFIX(stabilityCondition_notRespected): return "pledged buffer stability condition is not respected"; 46 | case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; 47 | case PREFIX(dictionary_wrong): return "Dictionary mismatch"; 48 | case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples"; 49 | case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; 50 | case PREFIX(srcSize_wrong): return "Src size is incorrect"; 51 | case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer"; 52 | case PREFIX(noForwardProgress_destFull): return "Operation made no progress over multiple calls, due to output buffer being full"; 53 | case PREFIX(noForwardProgress_inputEmpty): return "Operation made no progress over multiple calls, due to input being empty"; 54 | /* following error codes are not stable and may be removed or changed in a future version */ 55 | case PREFIX(frameIndex_tooLarge): return "Frame index is too large"; 56 | case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking"; 57 | case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong"; 58 | case PREFIX(srcBuffer_wrong): return "Source buffer is wrong"; 59 | case PREFIX(sequenceProducer_failed): return "Block-level external sequence producer returned an error code"; 60 | case PREFIX(externalSequences_invalid): return "External sequences are not valid"; 61 | case PREFIX(maxCode): 62 | default: return notErrorCode; 63 | } 64 | #endif 65 | } 66 | 67 | #endif /* USE_EXTERNAL_ZSTD */ 68 | -------------------------------------------------------------------------------- /error_private.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | /* Note : this module is expected to remain private, do not expose it */ 13 | 14 | #ifndef ERROR_H_MODULE 15 | #define ERROR_H_MODULE 16 | 17 | /* **************************************** 18 | * Dependencies 19 | ******************************************/ 20 | #include "zstd_errors.h" /* enum list */ 21 | #include "compiler.h" 22 | #include "debug.h" 23 | #include "zstd_deps.h" /* size_t */ 24 | 25 | /* **************************************** 26 | * Compiler-specific 27 | ******************************************/ 28 | #if defined(__GNUC__) 29 | # define ERR_STATIC static __attribute__((unused)) 30 | #elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) 31 | # define ERR_STATIC static inline 32 | #elif defined(_MSC_VER) 33 | # define ERR_STATIC static __inline 34 | #else 35 | # define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ 36 | #endif 37 | 38 | 39 | /*-**************************************** 40 | * Customization (error_public.h) 41 | ******************************************/ 42 | typedef ZSTD_ErrorCode ERR_enum; 43 | #define PREFIX(name) ZSTD_error_##name 44 | 45 | 46 | /*-**************************************** 47 | * Error codes handling 48 | ******************************************/ 49 | #undef ERROR /* already defined on Visual Studio */ 50 | #define ERROR(name) ZSTD_ERROR(name) 51 | #define ZSTD_ERROR(name) ((size_t)-PREFIX(name)) 52 | 53 | ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } 54 | 55 | ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); } 56 | 57 | /* check and forward error code */ 58 | #define CHECK_V_F(e, f) \ 59 | size_t const e = f; \ 60 | do { \ 61 | if (ERR_isError(e)) \ 62 | return e; \ 63 | } while (0) 64 | #define CHECK_F(f) do { CHECK_V_F(_var_err__, f); } while (0) 65 | 66 | 67 | /*-**************************************** 68 | * Error Strings 69 | ******************************************/ 70 | 71 | const char* ERR_getErrorString(ERR_enum code); /* error_private.c */ 72 | 73 | ERR_STATIC const char* ERR_getErrorName(size_t code) 74 | { 75 | return ERR_getErrorString(ERR_getErrorCode(code)); 76 | } 77 | 78 | /** 79 | * Ignore: this is an internal helper. 80 | * 81 | * This is a helper function to help force C99-correctness during compilation. 82 | * Under strict compilation modes, variadic macro arguments can't be empty. 83 | * However, variadic function arguments can be. Using a function therefore lets 84 | * us statically check that at least one (string) argument was passed, 85 | * independent of the compilation flags. 86 | */ 87 | static INLINE_KEYWORD UNUSED_ATTR 88 | void _force_has_format_string(const char *format, ...) { 89 | (void)format; 90 | } 91 | 92 | /** 93 | * Ignore: this is an internal helper. 94 | * 95 | * We want to force this function invocation to be syntactically correct, but 96 | * we don't want to force runtime evaluation of its arguments. 97 | */ 98 | #define _FORCE_HAS_FORMAT_STRING(...) \ 99 | do { \ 100 | if (0) { \ 101 | _force_has_format_string(__VA_ARGS__); \ 102 | } \ 103 | } while (0) 104 | 105 | #define ERR_QUOTE(str) #str 106 | 107 | /** 108 | * Return the specified error if the condition evaluates to true. 109 | * 110 | * In debug modes, prints additional information. 111 | * In order to do that (particularly, printing the conditional that failed), 112 | * this can't just wrap RETURN_ERROR(). 113 | */ 114 | #define RETURN_ERROR_IF(cond, err, ...) \ 115 | do { \ 116 | if (cond) { \ 117 | RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \ 118 | __FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \ 119 | _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ 120 | RAWLOG(3, ": " __VA_ARGS__); \ 121 | RAWLOG(3, "\n"); \ 122 | return ERROR(err); \ 123 | } \ 124 | } while (0) 125 | 126 | /** 127 | * Unconditionally return the specified error. 128 | * 129 | * In debug modes, prints additional information. 130 | */ 131 | #define RETURN_ERROR(err, ...) \ 132 | do { \ 133 | RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \ 134 | __FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \ 135 | _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ 136 | RAWLOG(3, ": " __VA_ARGS__); \ 137 | RAWLOG(3, "\n"); \ 138 | return ERROR(err); \ 139 | } while(0) 140 | 141 | /** 142 | * If the provided expression evaluates to an error code, returns that error code. 143 | * 144 | * In debug modes, prints additional information. 145 | */ 146 | #define FORWARD_IF_ERROR(err, ...) \ 147 | do { \ 148 | size_t const err_code = (err); \ 149 | if (ERR_isError(err_code)) { \ 150 | RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \ 151 | __FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \ 152 | _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ 153 | RAWLOG(3, ": " __VA_ARGS__); \ 154 | RAWLOG(3, "\n"); \ 155 | return err_code; \ 156 | } \ 157 | } while(0) 158 | 159 | #endif /* ERROR_H_MODULE */ 160 | 161 | #endif /* USE_EXTERNAL_ZSTD */ 162 | -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | package zstd 2 | 3 | /* 4 | #include "zstd.h" 5 | */ 6 | import "C" 7 | 8 | // ErrorCode is an error returned by the zstd library. 9 | type ErrorCode int 10 | 11 | // Error returns the error string given by zstd 12 | func (e ErrorCode) Error() string { 13 | return C.GoString(C.ZSTD_getErrorName(C.size_t(e))) 14 | } 15 | 16 | func cIsError(code int) bool { 17 | return int(C.ZSTD_isError(C.size_t(code))) != 0 18 | } 19 | 20 | // getError returns an error for the return code, or nil if it's not an error 21 | func getError(code int) error { 22 | if code < 0 && cIsError(code) { 23 | return ErrorCode(code) 24 | } 25 | return nil 26 | } 27 | 28 | // IsDstSizeTooSmallError returns whether the error correspond to zstd standard sDstSizeTooSmall error 29 | func IsDstSizeTooSmallError(e error) bool { 30 | if e != nil && e.Error() == "Destination buffer is too small" { 31 | return true 32 | } 33 | return false 34 | } 35 | -------------------------------------------------------------------------------- /errors_test.go: -------------------------------------------------------------------------------- 1 | package zstd 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | const ( 8 | // ErrorUpperBound is the upper bound to error number, currently only used in test 9 | // If this needs to be updated, check in zstd_errors.h what the max is 10 | ErrorUpperBound = 1000 11 | ) 12 | 13 | // TestFindIsDstSizeTooSmallError tests that there is at least one error code that 14 | // corresponds to dst size too small 15 | func TestFindIsDstSizeTooSmallError(t *testing.T) { 16 | found := 0 17 | for i := -1; i > -ErrorUpperBound; i-- { 18 | e := ErrorCode(i) 19 | if IsDstSizeTooSmallError(e) { 20 | found++ 21 | } 22 | } 23 | 24 | if found == 0 { 25 | t.Fatal("Couldn't find an error code for DstSizeTooSmall error, please make sure we didn't change the error string") 26 | } else if found > 1 { 27 | t.Fatal("IsDstSizeTooSmallError found multiple error codes matching, this shouldn't be the case") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /external_zstd.go: -------------------------------------------------------------------------------- 1 | //go:build external_libzstd 2 | // +build external_libzstd 3 | 4 | package zstd 5 | 6 | // #cgo CFLAGS: -DUSE_EXTERNAL_ZSTD 7 | // #cgo pkg-config: libzstd 8 | /* 9 | #include 10 | #if ZSTD_VERSION_NUMBER < 10400 11 | #error "ZSTD version >= 1.4 is required" 12 | #endif 13 | */ 14 | import "C" 15 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/DataDog/zstd 2 | 3 | go 1.14 4 | -------------------------------------------------------------------------------- /helpers_test.go: -------------------------------------------------------------------------------- 1 | package zstd 2 | 3 | /* 4 | From https://github.com/dustin/randbo 5 | All credits for the code below goes there :) (There wasn't a license so I'm distributing as is) 6 | */ 7 | 8 | import ( 9 | "io" 10 | "math/rand" 11 | "time" 12 | ) 13 | 14 | // randbytes creates a stream of non-crypto quality random bytes 15 | type randbytes struct { 16 | rand.Source 17 | } 18 | 19 | // NewRandBytes creates a new random reader with a time source. 20 | func NewRandBytes() io.Reader { 21 | return NewRandBytesFrom(rand.NewSource(time.Now().UnixNano())) 22 | } 23 | 24 | // NewRandBytesFrom creates a new reader from your own rand.Source 25 | func NewRandBytesFrom(src rand.Source) io.Reader { 26 | return &randbytes{src} 27 | } 28 | 29 | // Read satisfies io.Reader 30 | func (r *randbytes) Read(p []byte) (n int, err error) { 31 | todo := len(p) 32 | offset := 0 33 | for { 34 | val := int64(r.Int63()) 35 | for i := 0; i < 8; i++ { 36 | p[offset] = byte(val) 37 | todo-- 38 | if todo == 0 { 39 | return len(p), nil 40 | } 41 | offset++ 42 | val >>= 8 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /hist.c: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* ****************************************************************** 3 | * hist : Histogram functions 4 | * part of Finite State Entropy project 5 | * Copyright (c) Meta Platforms, Inc. and affiliates. 6 | * 7 | * You can contact the author at : 8 | * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy 9 | * - Public forum : https://groups.google.com/forum/#!forum/lz4c 10 | * 11 | * This source code is licensed under both the BSD-style license (found in the 12 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 13 | * in the COPYING file in the root directory of this source tree). 14 | * You may select, at your option, one of the above-listed licenses. 15 | ****************************************************************** */ 16 | 17 | /* --- dependencies --- */ 18 | #include "mem.h" /* U32, BYTE, etc. */ 19 | #include "debug.h" /* assert, DEBUGLOG */ 20 | #include "error_private.h" /* ERROR */ 21 | #include "hist.h" 22 | 23 | 24 | /* --- Error management --- */ 25 | unsigned HIST_isError(size_t code) { return ERR_isError(code); } 26 | 27 | /*-************************************************************** 28 | * Histogram functions 29 | ****************************************************************/ 30 | void HIST_add(unsigned* count, const void* src, size_t srcSize) 31 | { 32 | const BYTE* ip = (const BYTE*)src; 33 | const BYTE* const end = ip + srcSize; 34 | 35 | while (ip largestCount) largestCount = count[s]; 62 | } 63 | 64 | return largestCount; 65 | } 66 | 67 | typedef enum { trustInput, checkMaxSymbolValue } HIST_checkInput_e; 68 | 69 | /* HIST_count_parallel_wksp() : 70 | * store histogram into 4 intermediate tables, recombined at the end. 71 | * this design makes better use of OoO cpus, 72 | * and is noticeably faster when some values are heavily repeated. 73 | * But it needs some additional workspace for intermediate tables. 74 | * `workSpace` must be a U32 table of size >= HIST_WKSP_SIZE_U32. 75 | * @return : largest histogram frequency, 76 | * or an error code (notably when histogram's alphabet is larger than *maxSymbolValuePtr) */ 77 | static size_t HIST_count_parallel_wksp( 78 | unsigned* count, unsigned* maxSymbolValuePtr, 79 | const void* source, size_t sourceSize, 80 | HIST_checkInput_e check, 81 | U32* const workSpace) 82 | { 83 | const BYTE* ip = (const BYTE*)source; 84 | const BYTE* const iend = ip+sourceSize; 85 | size_t const countSize = (*maxSymbolValuePtr + 1) * sizeof(*count); 86 | unsigned max=0; 87 | U32* const Counting1 = workSpace; 88 | U32* const Counting2 = Counting1 + 256; 89 | U32* const Counting3 = Counting2 + 256; 90 | U32* const Counting4 = Counting3 + 256; 91 | 92 | /* safety checks */ 93 | assert(*maxSymbolValuePtr <= 255); 94 | if (!sourceSize) { 95 | ZSTD_memset(count, 0, countSize); 96 | *maxSymbolValuePtr = 0; 97 | return 0; 98 | } 99 | ZSTD_memset(workSpace, 0, 4*256*sizeof(unsigned)); 100 | 101 | /* by stripes of 16 bytes */ 102 | { U32 cached = MEM_read32(ip); ip += 4; 103 | while (ip < iend-15) { 104 | U32 c = cached; cached = MEM_read32(ip); ip += 4; 105 | Counting1[(BYTE) c ]++; 106 | Counting2[(BYTE)(c>>8) ]++; 107 | Counting3[(BYTE)(c>>16)]++; 108 | Counting4[ c>>24 ]++; 109 | c = cached; cached = MEM_read32(ip); ip += 4; 110 | Counting1[(BYTE) c ]++; 111 | Counting2[(BYTE)(c>>8) ]++; 112 | Counting3[(BYTE)(c>>16)]++; 113 | Counting4[ c>>24 ]++; 114 | c = cached; cached = MEM_read32(ip); ip += 4; 115 | Counting1[(BYTE) c ]++; 116 | Counting2[(BYTE)(c>>8) ]++; 117 | Counting3[(BYTE)(c>>16)]++; 118 | Counting4[ c>>24 ]++; 119 | c = cached; cached = MEM_read32(ip); ip += 4; 120 | Counting1[(BYTE) c ]++; 121 | Counting2[(BYTE)(c>>8) ]++; 122 | Counting3[(BYTE)(c>>16)]++; 123 | Counting4[ c>>24 ]++; 124 | } 125 | ip-=4; 126 | } 127 | 128 | /* finish last symbols */ 129 | while (ip max) max = Counting1[s]; 135 | } } 136 | 137 | { unsigned maxSymbolValue = 255; 138 | while (!Counting1[maxSymbolValue]) maxSymbolValue--; 139 | if (check && maxSymbolValue > *maxSymbolValuePtr) return ERROR(maxSymbolValue_tooSmall); 140 | *maxSymbolValuePtr = maxSymbolValue; 141 | ZSTD_memmove(count, Counting1, countSize); /* in case count & Counting1 are overlapping */ 142 | } 143 | return (size_t)max; 144 | } 145 | 146 | /* HIST_countFast_wksp() : 147 | * Same as HIST_countFast(), but using an externally provided scratch buffer. 148 | * `workSpace` is a writable buffer which must be 4-bytes aligned, 149 | * `workSpaceSize` must be >= HIST_WKSP_SIZE 150 | */ 151 | size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, 152 | const void* source, size_t sourceSize, 153 | void* workSpace, size_t workSpaceSize) 154 | { 155 | if (sourceSize < 1500) /* heuristic threshold */ 156 | return HIST_count_simple(count, maxSymbolValuePtr, source, sourceSize); 157 | if ((size_t)workSpace & 3) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */ 158 | if (workSpaceSize < HIST_WKSP_SIZE) return ERROR(workSpace_tooSmall); 159 | return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, trustInput, (U32*)workSpace); 160 | } 161 | 162 | /* HIST_count_wksp() : 163 | * Same as HIST_count(), but using an externally provided scratch buffer. 164 | * `workSpace` size must be table of >= HIST_WKSP_SIZE_U32 unsigned */ 165 | size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr, 166 | const void* source, size_t sourceSize, 167 | void* workSpace, size_t workSpaceSize) 168 | { 169 | if ((size_t)workSpace & 3) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */ 170 | if (workSpaceSize < HIST_WKSP_SIZE) return ERROR(workSpace_tooSmall); 171 | if (*maxSymbolValuePtr < 255) 172 | return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, checkMaxSymbolValue, (U32*)workSpace); 173 | *maxSymbolValuePtr = 255; 174 | return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace, workSpaceSize); 175 | } 176 | 177 | #ifndef ZSTD_NO_UNUSED_FUNCTIONS 178 | /* fast variant (unsafe : won't check if src contains values beyond count[] limit) */ 179 | size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr, 180 | const void* source, size_t sourceSize) 181 | { 182 | unsigned tmpCounters[HIST_WKSP_SIZE_U32]; 183 | return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters)); 184 | } 185 | 186 | size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr, 187 | const void* src, size_t srcSize) 188 | { 189 | unsigned tmpCounters[HIST_WKSP_SIZE_U32]; 190 | return HIST_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters, sizeof(tmpCounters)); 191 | } 192 | #endif 193 | 194 | #endif /* USE_EXTERNAL_ZSTD */ 195 | -------------------------------------------------------------------------------- /hist.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* ****************************************************************** 3 | * hist : Histogram functions 4 | * part of Finite State Entropy project 5 | * Copyright (c) Meta Platforms, Inc. and affiliates. 6 | * 7 | * You can contact the author at : 8 | * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy 9 | * - Public forum : https://groups.google.com/forum/#!forum/lz4c 10 | * 11 | * This source code is licensed under both the BSD-style license (found in the 12 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 13 | * in the COPYING file in the root directory of this source tree). 14 | * You may select, at your option, one of the above-listed licenses. 15 | ****************************************************************** */ 16 | 17 | /* --- dependencies --- */ 18 | #include "zstd_deps.h" /* size_t */ 19 | 20 | 21 | /* --- simple histogram functions --- */ 22 | 23 | /*! HIST_count(): 24 | * Provides the precise count of each byte within a table 'count'. 25 | * 'count' is a table of unsigned int, of minimum size (*maxSymbolValuePtr+1). 26 | * Updates *maxSymbolValuePtr with actual largest symbol value detected. 27 | * @return : count of the most frequent symbol (which isn't identified). 28 | * or an error code, which can be tested using HIST_isError(). 29 | * note : if return == srcSize, there is only one symbol. 30 | */ 31 | size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr, 32 | const void* src, size_t srcSize); 33 | 34 | unsigned HIST_isError(size_t code); /**< tells if a return value is an error code */ 35 | 36 | 37 | /* --- advanced histogram functions --- */ 38 | 39 | #define HIST_WKSP_SIZE_U32 1024 40 | #define HIST_WKSP_SIZE (HIST_WKSP_SIZE_U32 * sizeof(unsigned)) 41 | /** HIST_count_wksp() : 42 | * Same as HIST_count(), but using an externally provided scratch buffer. 43 | * Benefit is this function will use very little stack space. 44 | * `workSpace` is a writable buffer which must be 4-bytes aligned, 45 | * `workSpaceSize` must be >= HIST_WKSP_SIZE 46 | */ 47 | size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr, 48 | const void* src, size_t srcSize, 49 | void* workSpace, size_t workSpaceSize); 50 | 51 | /** HIST_countFast() : 52 | * same as HIST_count(), but blindly trusts that all byte values within src are <= *maxSymbolValuePtr. 53 | * This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr` 54 | */ 55 | size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr, 56 | const void* src, size_t srcSize); 57 | 58 | /** HIST_countFast_wksp() : 59 | * Same as HIST_countFast(), but using an externally provided scratch buffer. 60 | * `workSpace` is a writable buffer which must be 4-bytes aligned, 61 | * `workSpaceSize` must be >= HIST_WKSP_SIZE 62 | */ 63 | size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, 64 | const void* src, size_t srcSize, 65 | void* workSpace, size_t workSpaceSize); 66 | 67 | /*! HIST_count_simple() : 68 | * Same as HIST_countFast(), this function is unsafe, 69 | * and will segfault if any value within `src` is `> *maxSymbolValuePtr`. 70 | * It is also a bit slower for large inputs. 71 | * However, it does not need any additional memory (not even on stack). 72 | * @return : count of the most frequent symbol. 73 | * Note this function doesn't produce any error (i.e. it must succeed). 74 | */ 75 | unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, 76 | const void* src, size_t srcSize); 77 | 78 | /*! HIST_add() : 79 | * Lowest level: just add nb of occurrences of characters from @src into @count. 80 | * @count is not reset. @count array is presumed large enough (i.e. 1 KB). 81 | @ This function does not need any additional stack memory. 82 | */ 83 | void HIST_add(unsigned* count, const void* src, size_t srcSize); 84 | 85 | #endif /* USE_EXTERNAL_ZSTD */ 86 | -------------------------------------------------------------------------------- /pool.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef POOL_H 13 | #define POOL_H 14 | 15 | 16 | #include "zstd_deps.h" 17 | #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_customMem */ 18 | #include "zstd.h" 19 | 20 | typedef struct POOL_ctx_s POOL_ctx; 21 | 22 | /*! POOL_create() : 23 | * Create a thread pool with at most `numThreads` threads. 24 | * `numThreads` must be at least 1. 25 | * The maximum number of queued jobs before blocking is `queueSize`. 26 | * @return : POOL_ctx pointer on success, else NULL. 27 | */ 28 | POOL_ctx* POOL_create(size_t numThreads, size_t queueSize); 29 | 30 | POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, 31 | ZSTD_customMem customMem); 32 | 33 | /*! POOL_free() : 34 | * Free a thread pool returned by POOL_create(). 35 | */ 36 | void POOL_free(POOL_ctx* ctx); 37 | 38 | 39 | /*! POOL_joinJobs() : 40 | * Waits for all queued jobs to finish executing. 41 | */ 42 | void POOL_joinJobs(POOL_ctx* ctx); 43 | 44 | /*! POOL_resize() : 45 | * Expands or shrinks pool's number of threads. 46 | * This is more efficient than releasing + creating a new context, 47 | * since it tries to preserve and reuse existing threads. 48 | * `numThreads` must be at least 1. 49 | * @return : 0 when resize was successful, 50 | * !0 (typically 1) if there is an error. 51 | * note : only numThreads can be resized, queueSize remains unchanged. 52 | */ 53 | int POOL_resize(POOL_ctx* ctx, size_t numThreads); 54 | 55 | /*! POOL_sizeof() : 56 | * @return threadpool memory usage 57 | * note : compatible with NULL (returns 0 in this case) 58 | */ 59 | size_t POOL_sizeof(const POOL_ctx* ctx); 60 | 61 | /*! POOL_function : 62 | * The function type that can be added to a thread pool. 63 | */ 64 | typedef void (*POOL_function)(void*); 65 | 66 | /*! POOL_add() : 67 | * Add the job `function(opaque)` to the thread pool. `ctx` must be valid. 68 | * Possibly blocks until there is room in the queue. 69 | * Note : The function may be executed asynchronously, 70 | * therefore, `opaque` must live until function has been completed. 71 | */ 72 | void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque); 73 | 74 | 75 | /*! POOL_tryAdd() : 76 | * Add the job `function(opaque)` to thread pool _if_ a queue slot is available. 77 | * Returns immediately even if not (does not block). 78 | * @return : 1 if successful, 0 if not. 79 | */ 80 | int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque); 81 | 82 | #endif 83 | 84 | #endif /* USE_EXTERNAL_ZSTD */ 85 | -------------------------------------------------------------------------------- /portability_macros.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_PORTABILITY_MACROS_H 13 | #define ZSTD_PORTABILITY_MACROS_H 14 | 15 | /** 16 | * This header file contains macro definitions to support portability. 17 | * This header is shared between C and ASM code, so it MUST only 18 | * contain macro definitions. It MUST not contain any C code. 19 | * 20 | * This header ONLY defines macros to detect platforms/feature support. 21 | * 22 | */ 23 | 24 | 25 | /* compat. with non-clang compilers */ 26 | #ifndef __has_attribute 27 | #define __has_attribute(x) 0 28 | #endif 29 | 30 | /* compat. with non-clang compilers */ 31 | #ifndef __has_builtin 32 | # define __has_builtin(x) 0 33 | #endif 34 | 35 | /* compat. with non-clang compilers */ 36 | #ifndef __has_feature 37 | # define __has_feature(x) 0 38 | #endif 39 | 40 | /* detects whether we are being compiled under msan */ 41 | #ifndef ZSTD_MEMORY_SANITIZER 42 | # if __has_feature(memory_sanitizer) 43 | # define ZSTD_MEMORY_SANITIZER 1 44 | # else 45 | # define ZSTD_MEMORY_SANITIZER 0 46 | # endif 47 | #endif 48 | 49 | /* detects whether we are being compiled under asan */ 50 | #ifndef ZSTD_ADDRESS_SANITIZER 51 | # if __has_feature(address_sanitizer) 52 | # define ZSTD_ADDRESS_SANITIZER 1 53 | # elif defined(__SANITIZE_ADDRESS__) 54 | # define ZSTD_ADDRESS_SANITIZER 1 55 | # else 56 | # define ZSTD_ADDRESS_SANITIZER 0 57 | # endif 58 | #endif 59 | 60 | /* detects whether we are being compiled under dfsan */ 61 | #ifndef ZSTD_DATAFLOW_SANITIZER 62 | # if __has_feature(dataflow_sanitizer) 63 | # define ZSTD_DATAFLOW_SANITIZER 1 64 | # else 65 | # define ZSTD_DATAFLOW_SANITIZER 0 66 | # endif 67 | #endif 68 | 69 | /* Mark the internal assembly functions as hidden */ 70 | #ifdef __ELF__ 71 | # define ZSTD_HIDE_ASM_FUNCTION(func) .hidden func 72 | #elif defined(__APPLE__) 73 | # define ZSTD_HIDE_ASM_FUNCTION(func) .private_extern func 74 | #else 75 | # define ZSTD_HIDE_ASM_FUNCTION(func) 76 | #endif 77 | 78 | /* Compile time determination of BMI2 support */ 79 | #ifndef STATIC_BMI2 80 | # if defined(__BMI2__) 81 | # define STATIC_BMI2 1 82 | # elif defined(_MSC_VER) && defined(__AVX2__) 83 | # define STATIC_BMI2 1 /* MSVC does not have a BMI2 specific flag, but every CPU that supports AVX2 also supports BMI2 */ 84 | # endif 85 | #endif 86 | 87 | #ifndef STATIC_BMI2 88 | # define STATIC_BMI2 0 89 | #endif 90 | 91 | /* Enable runtime BMI2 dispatch based on the CPU. 92 | * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default. 93 | */ 94 | #ifndef DYNAMIC_BMI2 95 | # if ((defined(__clang__) && __has_attribute(__target__)) \ 96 | || (defined(__GNUC__) \ 97 | && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ 98 | && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)) \ 99 | && !defined(__BMI2__) 100 | # define DYNAMIC_BMI2 1 101 | # else 102 | # define DYNAMIC_BMI2 0 103 | # endif 104 | #endif 105 | 106 | /** 107 | * Only enable assembly for GNU C compatible compilers, 108 | * because other platforms may not support GAS assembly syntax. 109 | * 110 | * Only enable assembly for Linux / MacOS / Win32, other platforms may 111 | * work, but they haven't been tested. This could likely be 112 | * extended to BSD systems. 113 | * 114 | * Disable assembly when MSAN is enabled, because MSAN requires 115 | * 100% of code to be instrumented to work. 116 | */ 117 | #if defined(__GNUC__) 118 | # if defined(__linux__) || defined(__linux) || defined(__APPLE__) || defined(_WIN32) 119 | # if ZSTD_MEMORY_SANITIZER 120 | # define ZSTD_ASM_SUPPORTED 0 121 | # elif ZSTD_DATAFLOW_SANITIZER 122 | # define ZSTD_ASM_SUPPORTED 0 123 | # else 124 | # define ZSTD_ASM_SUPPORTED 1 125 | # endif 126 | # else 127 | # define ZSTD_ASM_SUPPORTED 0 128 | # endif 129 | #else 130 | # define ZSTD_ASM_SUPPORTED 0 131 | #endif 132 | 133 | /** 134 | * Determines whether we should enable assembly for x86-64 135 | * with BMI2. 136 | * 137 | * Enable if all of the following conditions hold: 138 | * - ASM hasn't been explicitly disabled by defining ZSTD_DISABLE_ASM 139 | * - Assembly is supported 140 | * - We are compiling for x86-64 and either: 141 | * - DYNAMIC_BMI2 is enabled 142 | * - BMI2 is supported at compile time 143 | */ 144 | #if !defined(ZSTD_DISABLE_ASM) && \ 145 | ZSTD_ASM_SUPPORTED && \ 146 | defined(__x86_64__) && \ 147 | (DYNAMIC_BMI2 || defined(__BMI2__)) 148 | # define ZSTD_ENABLE_ASM_X86_64_BMI2 1 149 | #else 150 | # define ZSTD_ENABLE_ASM_X86_64_BMI2 0 151 | #endif 152 | 153 | /* 154 | * For x86 ELF targets, add .note.gnu.property section for Intel CET in 155 | * assembly sources when CET is enabled. 156 | * 157 | * Additionally, any function that may be called indirectly must begin 158 | * with ZSTD_CET_ENDBRANCH. 159 | */ 160 | #if defined(__ELF__) && (defined(__x86_64__) || defined(__i386__)) \ 161 | && defined(__has_include) 162 | # if __has_include() 163 | # include 164 | # define ZSTD_CET_ENDBRANCH _CET_ENDBR 165 | # endif 166 | #endif 167 | 168 | #ifndef ZSTD_CET_ENDBRANCH 169 | # define ZSTD_CET_ENDBRANCH 170 | #endif 171 | 172 | #endif /* ZSTD_PORTABILITY_MACROS_H */ 173 | 174 | #endif /* USE_EXTERNAL_ZSTD */ 175 | -------------------------------------------------------------------------------- /threading.c: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /** 3 | * Copyright (c) 2016 Tino Reichardt 4 | * All rights reserved. 5 | * 6 | * You can contact the author at: 7 | * - zstdmt source repository: https://github.com/mcmilk/zstdmt 8 | * 9 | * This source code is licensed under both the BSD-style license (found in the 10 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 11 | * in the COPYING file in the root directory of this source tree). 12 | * You may select, at your option, one of the above-listed licenses. 13 | */ 14 | 15 | /** 16 | * This file will hold wrapper for systems, which do not support pthreads 17 | */ 18 | 19 | #include "threading.h" 20 | 21 | /* create fake symbol to avoid empty translation unit warning */ 22 | int g_ZSTD_threading_useless_symbol; 23 | 24 | #if defined(ZSTD_MULTITHREAD) && defined(_WIN32) 25 | 26 | /** 27 | * Windows minimalist Pthread Wrapper 28 | */ 29 | 30 | 31 | /* === Dependencies === */ 32 | #include 33 | #include 34 | 35 | 36 | /* === Implementation === */ 37 | 38 | typedef struct { 39 | void* (*start_routine)(void*); 40 | void* arg; 41 | int initialized; 42 | ZSTD_pthread_cond_t initialized_cond; 43 | ZSTD_pthread_mutex_t initialized_mutex; 44 | } ZSTD_thread_params_t; 45 | 46 | static unsigned __stdcall worker(void *arg) 47 | { 48 | void* (*start_routine)(void*); 49 | void* thread_arg; 50 | 51 | /* Initialized thread_arg and start_routine and signal main thread that we don't need it 52 | * to wait any longer. 53 | */ 54 | { 55 | ZSTD_thread_params_t* thread_param = (ZSTD_thread_params_t*)arg; 56 | thread_arg = thread_param->arg; 57 | start_routine = thread_param->start_routine; 58 | 59 | /* Signal main thread that we are running and do not depend on its memory anymore */ 60 | ZSTD_pthread_mutex_lock(&thread_param->initialized_mutex); 61 | thread_param->initialized = 1; 62 | ZSTD_pthread_cond_signal(&thread_param->initialized_cond); 63 | ZSTD_pthread_mutex_unlock(&thread_param->initialized_mutex); 64 | } 65 | 66 | start_routine(thread_arg); 67 | 68 | return 0; 69 | } 70 | 71 | int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, 72 | void* (*start_routine) (void*), void* arg) 73 | { 74 | ZSTD_thread_params_t thread_param; 75 | (void)unused; 76 | 77 | if (thread==NULL) return -1; 78 | *thread = NULL; 79 | 80 | thread_param.start_routine = start_routine; 81 | thread_param.arg = arg; 82 | thread_param.initialized = 0; 83 | 84 | /* Setup thread initialization synchronization */ 85 | if(ZSTD_pthread_cond_init(&thread_param.initialized_cond, NULL)) { 86 | /* Should never happen on Windows */ 87 | return -1; 88 | } 89 | if(ZSTD_pthread_mutex_init(&thread_param.initialized_mutex, NULL)) { 90 | /* Should never happen on Windows */ 91 | ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); 92 | return -1; 93 | } 94 | 95 | /* Spawn thread */ 96 | *thread = (HANDLE)_beginthreadex(NULL, 0, worker, &thread_param, 0, NULL); 97 | if (*thread==NULL) { 98 | ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex); 99 | ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); 100 | return errno; 101 | } 102 | 103 | /* Wait for thread to be initialized */ 104 | ZSTD_pthread_mutex_lock(&thread_param.initialized_mutex); 105 | while(!thread_param.initialized) { 106 | ZSTD_pthread_cond_wait(&thread_param.initialized_cond, &thread_param.initialized_mutex); 107 | } 108 | ZSTD_pthread_mutex_unlock(&thread_param.initialized_mutex); 109 | ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex); 110 | ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); 111 | 112 | return 0; 113 | } 114 | 115 | int ZSTD_pthread_join(ZSTD_pthread_t thread) 116 | { 117 | DWORD result; 118 | 119 | if (!thread) return 0; 120 | 121 | result = WaitForSingleObject(thread, INFINITE); 122 | CloseHandle(thread); 123 | 124 | switch (result) { 125 | case WAIT_OBJECT_0: 126 | return 0; 127 | case WAIT_ABANDONED: 128 | return EINVAL; 129 | default: 130 | return GetLastError(); 131 | } 132 | } 133 | 134 | #endif /* ZSTD_MULTITHREAD */ 135 | 136 | #if defined(ZSTD_MULTITHREAD) && DEBUGLEVEL >= 1 && !defined(_WIN32) 137 | 138 | #define ZSTD_DEPS_NEED_MALLOC 139 | #include "zstd_deps.h" 140 | 141 | int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr) 142 | { 143 | assert(mutex != NULL); 144 | *mutex = (pthread_mutex_t*)ZSTD_malloc(sizeof(pthread_mutex_t)); 145 | if (!*mutex) 146 | return 1; 147 | return pthread_mutex_init(*mutex, attr); 148 | } 149 | 150 | int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex) 151 | { 152 | assert(mutex != NULL); 153 | if (!*mutex) 154 | return 0; 155 | { 156 | int const ret = pthread_mutex_destroy(*mutex); 157 | ZSTD_free(*mutex); 158 | return ret; 159 | } 160 | } 161 | 162 | int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr) 163 | { 164 | assert(cond != NULL); 165 | *cond = (pthread_cond_t*)ZSTD_malloc(sizeof(pthread_cond_t)); 166 | if (!*cond) 167 | return 1; 168 | return pthread_cond_init(*cond, attr); 169 | } 170 | 171 | int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond) 172 | { 173 | assert(cond != NULL); 174 | if (!*cond) 175 | return 0; 176 | { 177 | int const ret = pthread_cond_destroy(*cond); 178 | ZSTD_free(*cond); 179 | return ret; 180 | } 181 | } 182 | 183 | #endif 184 | 185 | #endif /* USE_EXTERNAL_ZSTD */ 186 | -------------------------------------------------------------------------------- /threading.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /** 3 | * Copyright (c) 2016 Tino Reichardt 4 | * All rights reserved. 5 | * 6 | * You can contact the author at: 7 | * - zstdmt source repository: https://github.com/mcmilk/zstdmt 8 | * 9 | * This source code is licensed under both the BSD-style license (found in the 10 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 11 | * in the COPYING file in the root directory of this source tree). 12 | * You may select, at your option, one of the above-listed licenses. 13 | */ 14 | 15 | #ifndef THREADING_H_938743 16 | #define THREADING_H_938743 17 | 18 | #include "debug.h" 19 | 20 | #if defined(ZSTD_MULTITHREAD) && defined(_WIN32) 21 | 22 | /** 23 | * Windows minimalist Pthread Wrapper 24 | */ 25 | #ifdef WINVER 26 | # undef WINVER 27 | #endif 28 | #define WINVER 0x0600 29 | 30 | #ifdef _WIN32_WINNT 31 | # undef _WIN32_WINNT 32 | #endif 33 | #define _WIN32_WINNT 0x0600 34 | 35 | #ifndef WIN32_LEAN_AND_MEAN 36 | # define WIN32_LEAN_AND_MEAN 37 | #endif 38 | 39 | #undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ 40 | #include 41 | #undef ERROR 42 | #define ERROR(name) ZSTD_ERROR(name) 43 | 44 | 45 | /* mutex */ 46 | #define ZSTD_pthread_mutex_t CRITICAL_SECTION 47 | #define ZSTD_pthread_mutex_init(a, b) ((void)(b), InitializeCriticalSection((a)), 0) 48 | #define ZSTD_pthread_mutex_destroy(a) DeleteCriticalSection((a)) 49 | #define ZSTD_pthread_mutex_lock(a) EnterCriticalSection((a)) 50 | #define ZSTD_pthread_mutex_unlock(a) LeaveCriticalSection((a)) 51 | 52 | /* condition variable */ 53 | #define ZSTD_pthread_cond_t CONDITION_VARIABLE 54 | #define ZSTD_pthread_cond_init(a, b) ((void)(b), InitializeConditionVariable((a)), 0) 55 | #define ZSTD_pthread_cond_destroy(a) ((void)(a)) 56 | #define ZSTD_pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE) 57 | #define ZSTD_pthread_cond_signal(a) WakeConditionVariable((a)) 58 | #define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a)) 59 | 60 | /* ZSTD_pthread_create() and ZSTD_pthread_join() */ 61 | typedef HANDLE ZSTD_pthread_t; 62 | 63 | int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, 64 | void* (*start_routine) (void*), void* arg); 65 | 66 | int ZSTD_pthread_join(ZSTD_pthread_t thread); 67 | 68 | /** 69 | * add here more wrappers as required 70 | */ 71 | 72 | #elif defined(ZSTD_MULTITHREAD) /* posix assumed ; need a better detection method */ 73 | /* === POSIX Systems === */ 74 | # include 75 | 76 | #if DEBUGLEVEL < 1 77 | 78 | #define ZSTD_pthread_mutex_t pthread_mutex_t 79 | #define ZSTD_pthread_mutex_init(a, b) pthread_mutex_init((a), (b)) 80 | #define ZSTD_pthread_mutex_destroy(a) pthread_mutex_destroy((a)) 81 | #define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock((a)) 82 | #define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock((a)) 83 | 84 | #define ZSTD_pthread_cond_t pthread_cond_t 85 | #define ZSTD_pthread_cond_init(a, b) pthread_cond_init((a), (b)) 86 | #define ZSTD_pthread_cond_destroy(a) pthread_cond_destroy((a)) 87 | #define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait((a), (b)) 88 | #define ZSTD_pthread_cond_signal(a) pthread_cond_signal((a)) 89 | #define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast((a)) 90 | 91 | #define ZSTD_pthread_t pthread_t 92 | #define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) 93 | #define ZSTD_pthread_join(a) pthread_join((a),NULL) 94 | 95 | #else /* DEBUGLEVEL >= 1 */ 96 | 97 | /* Debug implementation of threading. 98 | * In this implementation we use pointers for mutexes and condition variables. 99 | * This way, if we forget to init/destroy them the program will crash or ASAN 100 | * will report leaks. 101 | */ 102 | 103 | #define ZSTD_pthread_mutex_t pthread_mutex_t* 104 | int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr); 105 | int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex); 106 | #define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock(*(a)) 107 | #define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock(*(a)) 108 | 109 | #define ZSTD_pthread_cond_t pthread_cond_t* 110 | int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr); 111 | int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond); 112 | #define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait(*(a), *(b)) 113 | #define ZSTD_pthread_cond_signal(a) pthread_cond_signal(*(a)) 114 | #define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast(*(a)) 115 | 116 | #define ZSTD_pthread_t pthread_t 117 | #define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) 118 | #define ZSTD_pthread_join(a) pthread_join((a),NULL) 119 | 120 | #endif 121 | 122 | #else /* ZSTD_MULTITHREAD not defined */ 123 | /* No multithreading support */ 124 | 125 | typedef int ZSTD_pthread_mutex_t; 126 | #define ZSTD_pthread_mutex_init(a, b) ((void)(a), (void)(b), 0) 127 | #define ZSTD_pthread_mutex_destroy(a) ((void)(a)) 128 | #define ZSTD_pthread_mutex_lock(a) ((void)(a)) 129 | #define ZSTD_pthread_mutex_unlock(a) ((void)(a)) 130 | 131 | typedef int ZSTD_pthread_cond_t; 132 | #define ZSTD_pthread_cond_init(a, b) ((void)(a), (void)(b), 0) 133 | #define ZSTD_pthread_cond_destroy(a) ((void)(a)) 134 | #define ZSTD_pthread_cond_wait(a, b) ((void)(a), (void)(b)) 135 | #define ZSTD_pthread_cond_signal(a) ((void)(a)) 136 | #define ZSTD_pthread_cond_broadcast(a) ((void)(a)) 137 | 138 | /* do not use ZSTD_pthread_t */ 139 | 140 | #endif /* ZSTD_MULTITHREAD */ 141 | 142 | 143 | #endif /* THREADING_H_938743 */ 144 | 145 | #endif /* USE_EXTERNAL_ZSTD */ 146 | -------------------------------------------------------------------------------- /tools/flatten_imports.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | This script rewites the zstd source files to flatten imports 4 | """ 5 | 6 | import glob 7 | 8 | def rewrite_file(path): 9 | results = [] 10 | with open(path, "r") as f: 11 | for l in f.readlines(): 12 | line_no_space = l.replace(" ", "") 13 | if not line_no_space.startswith('#include"..'): 14 | results.append(l) # Do nothing 15 | else: 16 | # Include line, rewrite it 17 | new_path = l.split('"')[1] 18 | end = l.split('"')[-1] 19 | new_path = new_path.split("/")[-1] 20 | results.append('#include "' + new_path + '"' + end) 21 | with open(path, "w") as f: 22 | for l in results: 23 | f.write(l) 24 | 25 | 26 | if __name__ == "__main__": 27 | for file in glob.glob("*.c") + glob.glob("*.h") + glob.glob("*.S"): 28 | rewrite_file(file) 29 | -------------------------------------------------------------------------------- /tools/insert_libzstd_ifdefs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | This script rewites the zstd source files to enclose the source code 4 | inside a #ifndef USE_EXTERNAL_ZSTD. 5 | 6 | The goal of that is to avoid compiling vendored zstd source files 7 | when we compile the library against an externally provided libzstd. 8 | """ 9 | import sys 10 | import glob 11 | 12 | FLAG="USE_EXTERNAL_ZSTD" 13 | 14 | HEADER=f"""#ifndef {FLAG} 15 | """ 16 | 17 | ZSTD_H_FOOTER=f""" 18 | #else /* {FLAG} */ 19 | #include_next 20 | #endif /* {FLAG} */ 21 | """ 22 | 23 | FOOTER=f""" 24 | #endif /* {FLAG} */ 25 | """ 26 | 27 | def patch_file_content(filename, content): 28 | new_content = "" 29 | if not content.startswith(HEADER): 30 | new_content += HEADER 31 | new_content+=content 32 | footer = ZSTD_H_FOOTER if filename == "zstd.h" else FOOTER 33 | if not content.endswith(footer): 34 | new_content += footer 35 | return new_content 36 | 37 | def insert_ifdefs(file): 38 | with open(file, "r") as fd: 39 | content=fd.read() 40 | with open(file, "w") as fd: 41 | fd.write(patch_file_content(file, content)) 42 | 43 | if __name__ == "__main__": 44 | for file in glob.glob("*.c") + glob.glob("*.h"): 45 | insert_ifdefs(file) 46 | -------------------------------------------------------------------------------- /travis_test_32.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Get utilities 3 | #yum -y -q -e 0 install wget tar unzip gcc 4 | apt-get update 5 | apt-get -y install wget tar unzip gcc 6 | 7 | # Get Go 8 | wget -q https://dl.google.com/go/go1.13.linux-386.tar.gz 9 | tar -C /usr/local -xzf go1.13.linux-386.tar.gz 10 | export PATH=$PATH:/usr/local/go/bin 11 | 12 | # Get payload 13 | wget -q https://github.com/DataDog/zstd/files/2246767/mr.zip 14 | unzip mr.zip 15 | 16 | # Build and run tests 17 | go build 18 | DISABLE_BIG_TESTS=1 PAYLOAD=$(pwd)/mr go test -v 19 | DISABLE_BIG_TESTS=1 PAYLOAD=$(pwd)/mr go test -bench . 20 | -------------------------------------------------------------------------------- /update.txt: -------------------------------------------------------------------------------- 1 | ./lib/common/bitstream.h 2 | ./lib/common/compiler.h 3 | ./lib/compress/zstd_compress_internal.h 4 | ./lib/compress/zstd_fast.h 5 | ./lib/compress/zstd_double_fast.h 6 | ./lib/compress/zstd_lazy.h 7 | ./lib/compress/zstd_ldm.h 8 | ./lib/dictBuilder/cover.c 9 | ./lib/dictBuilder/divsufsort.c 10 | ./lib/dictBuilder/divsufsort.h 11 | ./lib/common/entropy_common.c 12 | ./lib/common/error_private.c 13 | ./lib/common/error_private.h 14 | ./lib/compress/fse_compress.c 15 | ./lib/common/fse_decompress.c 16 | ./lib/common/fse.h 17 | ./lib/compress/huf_compress.c 18 | ./lib/decompress/huf_decompress.c 19 | ./lib/common/huf.h 20 | ./lib/common/mem.h 21 | ./lib/common/pool.c 22 | ./lib/common/pool.h 23 | ./lib/common/threading.c 24 | ./lib/common/threading.h 25 | ./lib/common/xxhash.c 26 | ./lib/common/xxhash.h 27 | ./lib/deprecated/zbuff_common.c 28 | ./lib/deprecated/zbuff_compress.c 29 | ./lib/deprecated/zbuff_decompress.c 30 | ./lib/deprecated/zbuff.h 31 | ./lib/dictBuilder/zdict.c 32 | ./lib/dictBuilder/zdict.h 33 | ./lib/common/zstd_common.c 34 | ./lib/compress/zstd_compress.c 35 | ./lib/decompress/zstd_decompress.c 36 | ./lib/common/zstd_errors.h 37 | ./lib/zstd.h 38 | ./lib/common/zstd_internal.h 39 | ./lib/legacy/zstd_legacy.h 40 | ./lib/compress/zstd_opt.c 41 | ./lib/compress/zstd_opt.h 42 | ./lib/legacy/zstd_v01.c 43 | ./lib/legacy/zstd_v01.h 44 | ./lib/legacy/zstd_v02.c 45 | ./lib/legacy/zstd_v02.h 46 | ./lib/legacy/zstd_v03.c 47 | ./lib/legacy/zstd_v03.h 48 | ./lib/legacy/zstd_v04.c 49 | ./lib/legacy/zstd_v04.h 50 | ./lib/legacy/zstd_v05.c 51 | ./lib/legacy/zstd_v05.h 52 | ./lib/legacy/zstd_v06.c 53 | ./lib/legacy/zstd_v06.h 54 | ./lib/legacy/zstd_v07.c 55 | ./lib/legacy/zstd_v07.h 56 | 57 | -------------------------------------------------------------------------------- /xxhash.c: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * xxHash - Extremely Fast Hash algorithm 4 | * Copyright (c) Yann Collet - Meta Platforms, Inc 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | /* 13 | * xxhash.c instantiates functions defined in xxhash.h 14 | */ 15 | 16 | #define XXH_STATIC_LINKING_ONLY /* access advanced declarations */ 17 | #define XXH_IMPLEMENTATION /* access definitions */ 18 | 19 | #include "xxhash.h" 20 | 21 | #endif /* USE_EXTERNAL_ZSTD */ 22 | -------------------------------------------------------------------------------- /zbuff_common.c: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | /*-************************************* 13 | * Dependencies 14 | ***************************************/ 15 | #include "error_private.h" 16 | #include "zbuff.h" 17 | 18 | /*-**************************************** 19 | * ZBUFF Error Management (deprecated) 20 | ******************************************/ 21 | 22 | /*! ZBUFF_isError() : 23 | * tells if a return value is an error code */ 24 | unsigned ZBUFF_isError(size_t errorCode) { return ERR_isError(errorCode); } 25 | /*! ZBUFF_getErrorName() : 26 | * provides error code string from function result (useful for debugging) */ 27 | const char* ZBUFF_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } 28 | 29 | #endif /* USE_EXTERNAL_ZSTD */ 30 | -------------------------------------------------------------------------------- /zbuff_compress.c: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | 13 | 14 | /* ************************************* 15 | * Dependencies 16 | ***************************************/ 17 | #define ZBUFF_STATIC_LINKING_ONLY 18 | #include "zbuff.h" 19 | #include "error_private.h" 20 | 21 | 22 | /*-*********************************************************** 23 | * Streaming compression 24 | * 25 | * A ZBUFF_CCtx object is required to track streaming operation. 26 | * Use ZBUFF_createCCtx() and ZBUFF_freeCCtx() to create/release resources. 27 | * Use ZBUFF_compressInit() to start a new compression operation. 28 | * ZBUFF_CCtx objects can be reused multiple times. 29 | * 30 | * Use ZBUFF_compressContinue() repetitively to consume your input. 31 | * *srcSizePtr and *dstCapacityPtr can be any size. 32 | * The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr. 33 | * Note that it may not consume the entire input, in which case it's up to the caller to call again the function with remaining input. 34 | * The content of dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters or change dst . 35 | * @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency) 36 | * or an error code, which can be tested using ZBUFF_isError(). 37 | * 38 | * ZBUFF_compressFlush() can be used to instruct ZBUFF to compress and output whatever remains within its buffer. 39 | * Note that it will not output more than *dstCapacityPtr. 40 | * Therefore, some content might still be left into its internal buffer if dst buffer is too small. 41 | * @return : nb of bytes still present into internal buffer (0 if it's empty) 42 | * or an error code, which can be tested using ZBUFF_isError(). 43 | * 44 | * ZBUFF_compressEnd() instructs to finish a frame. 45 | * It will perform a flush and write frame epilogue. 46 | * Similar to ZBUFF_compressFlush(), it may not be able to output the entire internal buffer content if *dstCapacityPtr is too small. 47 | * @return : nb of bytes still present into internal buffer (0 if it's empty) 48 | * or an error code, which can be tested using ZBUFF_isError(). 49 | * 50 | * Hint : recommended buffer sizes (not compulsory) 51 | * input : ZSTD_BLOCKSIZE_MAX (128 KB), internal unit size, it improves latency to use this value. 52 | * output : ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + ZBUFF_endFrameSize : ensures it's always possible to write/flush/end a full block at best speed. 53 | * ***********************************************************/ 54 | 55 | ZBUFF_CCtx* ZBUFF_createCCtx(void) 56 | { 57 | return ZSTD_createCStream(); 58 | } 59 | 60 | ZBUFF_CCtx* ZBUFF_createCCtx_advanced(ZSTD_customMem customMem) 61 | { 62 | return ZSTD_createCStream_advanced(customMem); 63 | } 64 | 65 | size_t ZBUFF_freeCCtx(ZBUFF_CCtx* zbc) 66 | { 67 | return ZSTD_freeCStream(zbc); 68 | } 69 | 70 | 71 | /* ====== Initialization ====== */ 72 | 73 | size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, 74 | const void* dict, size_t dictSize, 75 | ZSTD_parameters params, unsigned long long pledgedSrcSize) 76 | { 77 | if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* preserve "0 == unknown" behavior */ 78 | FORWARD_IF_ERROR(ZSTD_CCtx_reset(zbc, ZSTD_reset_session_only), ""); 79 | FORWARD_IF_ERROR(ZSTD_CCtx_setPledgedSrcSize(zbc, pledgedSrcSize), ""); 80 | 81 | FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), ""); 82 | FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_windowLog, params.cParams.windowLog), ""); 83 | FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_hashLog, params.cParams.hashLog), ""); 84 | FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_chainLog, params.cParams.chainLog), ""); 85 | FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_searchLog, params.cParams.searchLog), ""); 86 | FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_minMatch, params.cParams.minMatch), ""); 87 | FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_targetLength, params.cParams.targetLength), ""); 88 | FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_strategy, params.cParams.strategy), ""); 89 | 90 | FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_contentSizeFlag, params.fParams.contentSizeFlag), ""); 91 | FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_checksumFlag, params.fParams.checksumFlag), ""); 92 | FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_dictIDFlag, params.fParams.noDictIDFlag), ""); 93 | 94 | FORWARD_IF_ERROR(ZSTD_CCtx_loadDictionary(zbc, dict, dictSize), ""); 95 | return 0; 96 | } 97 | 98 | size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* zbc, const void* dict, size_t dictSize, int compressionLevel) 99 | { 100 | FORWARD_IF_ERROR(ZSTD_CCtx_reset(zbc, ZSTD_reset_session_only), ""); 101 | FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_compressionLevel, compressionLevel), ""); 102 | FORWARD_IF_ERROR(ZSTD_CCtx_loadDictionary(zbc, dict, dictSize), ""); 103 | return 0; 104 | } 105 | 106 | size_t ZBUFF_compressInit(ZBUFF_CCtx* zbc, int compressionLevel) 107 | { 108 | return ZSTD_initCStream(zbc, compressionLevel); 109 | } 110 | 111 | /* ====== Compression ====== */ 112 | 113 | 114 | size_t ZBUFF_compressContinue(ZBUFF_CCtx* zbc, 115 | void* dst, size_t* dstCapacityPtr, 116 | const void* src, size_t* srcSizePtr) 117 | { 118 | size_t result; 119 | ZSTD_outBuffer outBuff; 120 | ZSTD_inBuffer inBuff; 121 | outBuff.dst = dst; 122 | outBuff.pos = 0; 123 | outBuff.size = *dstCapacityPtr; 124 | inBuff.src = src; 125 | inBuff.pos = 0; 126 | inBuff.size = *srcSizePtr; 127 | result = ZSTD_compressStream(zbc, &outBuff, &inBuff); 128 | *dstCapacityPtr = outBuff.pos; 129 | *srcSizePtr = inBuff.pos; 130 | return result; 131 | } 132 | 133 | 134 | 135 | /* ====== Finalize ====== */ 136 | 137 | size_t ZBUFF_compressFlush(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr) 138 | { 139 | size_t result; 140 | ZSTD_outBuffer outBuff; 141 | outBuff.dst = dst; 142 | outBuff.pos = 0; 143 | outBuff.size = *dstCapacityPtr; 144 | result = ZSTD_flushStream(zbc, &outBuff); 145 | *dstCapacityPtr = outBuff.pos; 146 | return result; 147 | } 148 | 149 | 150 | size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr) 151 | { 152 | size_t result; 153 | ZSTD_outBuffer outBuff; 154 | outBuff.dst = dst; 155 | outBuff.pos = 0; 156 | outBuff.size = *dstCapacityPtr; 157 | result = ZSTD_endStream(zbc, &outBuff); 158 | *dstCapacityPtr = outBuff.pos; 159 | return result; 160 | } 161 | 162 | 163 | 164 | /* ************************************* 165 | * Tool functions 166 | ***************************************/ 167 | size_t ZBUFF_recommendedCInSize(void) { return ZSTD_CStreamInSize(); } 168 | size_t ZBUFF_recommendedCOutSize(void) { return ZSTD_CStreamOutSize(); } 169 | 170 | #endif /* USE_EXTERNAL_ZSTD */ 171 | -------------------------------------------------------------------------------- /zbuff_decompress.c: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | 13 | 14 | /* ************************************* 15 | * Dependencies 16 | ***************************************/ 17 | #define ZSTD_DISABLE_DEPRECATE_WARNINGS /* suppress warning on ZSTD_initDStream_usingDict */ 18 | #include "zstd.h" /* ZSTD_CStream, ZSTD_DStream, ZSTDLIB_API */ 19 | #define ZBUFF_STATIC_LINKING_ONLY 20 | #include "zbuff.h" 21 | 22 | 23 | ZBUFF_DCtx* ZBUFF_createDCtx(void) 24 | { 25 | return ZSTD_createDStream(); 26 | } 27 | 28 | ZBUFF_DCtx* ZBUFF_createDCtx_advanced(ZSTD_customMem customMem) 29 | { 30 | return ZSTD_createDStream_advanced(customMem); 31 | } 32 | 33 | size_t ZBUFF_freeDCtx(ZBUFF_DCtx* zbd) 34 | { 35 | return ZSTD_freeDStream(zbd); 36 | } 37 | 38 | 39 | /* *** Initialization *** */ 40 | 41 | size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* zbd, const void* dict, size_t dictSize) 42 | { 43 | return ZSTD_initDStream_usingDict(zbd, dict, dictSize); 44 | } 45 | 46 | size_t ZBUFF_decompressInit(ZBUFF_DCtx* zbd) 47 | { 48 | return ZSTD_initDStream(zbd); 49 | } 50 | 51 | 52 | /* *** Decompression *** */ 53 | 54 | size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbd, 55 | void* dst, size_t* dstCapacityPtr, 56 | const void* src, size_t* srcSizePtr) 57 | { 58 | ZSTD_outBuffer outBuff; 59 | ZSTD_inBuffer inBuff; 60 | size_t result; 61 | outBuff.dst = dst; 62 | outBuff.pos = 0; 63 | outBuff.size = *dstCapacityPtr; 64 | inBuff.src = src; 65 | inBuff.pos = 0; 66 | inBuff.size = *srcSizePtr; 67 | result = ZSTD_decompressStream(zbd, &outBuff, &inBuff); 68 | *dstCapacityPtr = outBuff.pos; 69 | *srcSizePtr = inBuff.pos; 70 | return result; 71 | } 72 | 73 | 74 | /* ************************************* 75 | * Tool functions 76 | ***************************************/ 77 | size_t ZBUFF_recommendedDInSize(void) { return ZSTD_DStreamInSize(); } 78 | size_t ZBUFF_recommendedDOutSize(void) { return ZSTD_DStreamOutSize(); } 79 | 80 | #endif /* USE_EXTERNAL_ZSTD */ 81 | -------------------------------------------------------------------------------- /zstd.go: -------------------------------------------------------------------------------- 1 | package zstd 2 | 3 | /* 4 | // support decoding of "legacy" zstd payloads from versions [0.4, 0.8], matching the 5 | // default configuration of the zstd command line tool: 6 | // https://github.com/facebook/zstd/blob/dev/programs/README.md 7 | #cgo CFLAGS: -DZSTD_LEGACY_SUPPORT=4 -DZSTD_MULTITHREAD=1 8 | 9 | #include "zstd.h" 10 | */ 11 | import "C" 12 | import ( 13 | "bytes" 14 | "errors" 15 | "io/ioutil" 16 | "unsafe" 17 | ) 18 | 19 | // Defines best and standard values for zstd cli 20 | const ( 21 | BestSpeed = 1 22 | BestCompression = 20 23 | DefaultCompression = 5 24 | ) 25 | 26 | var ( 27 | // ErrEmptySlice is returned when there is nothing to compress 28 | ErrEmptySlice = errors.New("Bytes slice is empty") 29 | ) 30 | 31 | const ( 32 | // decompressSizeBufferLimit is the limit we set on creating a decompression buffer for the Decompress API 33 | // This is made to prevent DOS from maliciously-created payloads (aka zipbomb). 34 | // For large payloads with a compression ratio > 10, you can do your own allocation and pass it to the method: 35 | // dst := make([]byte, 1GB) 36 | // decompressed, err := zstd.Decompress(dst, src) 37 | decompressSizeBufferLimit = 1000 * 1000 38 | 39 | zstdFrameHeaderSizeMin = 2 // From zstd.h. Since it's experimental API, hardcoding it 40 | ) 41 | 42 | // CompressBound returns the worst case size needed for a destination buffer, 43 | // which can be used to preallocate a destination buffer or select a previously 44 | // allocated buffer from a pool. 45 | // See zstd.h to mirror implementation of ZSTD_COMPRESSBOUND 46 | func CompressBound(srcSize int) int { 47 | lowLimit := 128 << 10 // 128 kB 48 | var margin int 49 | if srcSize < lowLimit { 50 | margin = (lowLimit - srcSize) >> 11 51 | } 52 | return srcSize + (srcSize >> 8) + margin 53 | } 54 | 55 | // cCompressBound is a cgo call to check the go implementation above against the c code. 56 | func cCompressBound(srcSize int) int { 57 | return int(C.ZSTD_compressBound(C.size_t(srcSize))) 58 | } 59 | 60 | // decompressSizeHint tries to give a hint on how much of the output buffer size we should have 61 | // based on zstd frame descriptors. To prevent DOS from maliciously-created payloads, limit the size 62 | func decompressSizeHint(src []byte) int { 63 | // 1 MB or 50x input size 64 | upperBound := 50 * len(src) 65 | if upperBound < decompressSizeBufferLimit { 66 | upperBound = decompressSizeBufferLimit 67 | } 68 | 69 | hint := upperBound 70 | if len(src) >= zstdFrameHeaderSizeMin { 71 | hint = int(C.ZSTD_getFrameContentSize(unsafe.Pointer(&src[0]), C.size_t(len(src)))) 72 | if hint < 0 { // On error, just use upperBound 73 | hint = upperBound 74 | } 75 | if hint == 0 { // When compressing the empty slice, we need an output of at least 1 to pass down to the C lib 76 | hint = 1 77 | } 78 | } 79 | 80 | // Take the minimum of both 81 | if hint > upperBound { 82 | return upperBound 83 | } 84 | return hint 85 | } 86 | 87 | // Compress src into dst. If you have a buffer to use, you can pass it to 88 | // prevent allocation. If it is too small, or if nil is passed, a new buffer 89 | // will be allocated and returned. 90 | func Compress(dst, src []byte) ([]byte, error) { 91 | return CompressLevel(dst, src, DefaultCompression) 92 | } 93 | 94 | // CompressLevel is the same as Compress but you can pass a compression level 95 | func CompressLevel(dst, src []byte, level int) ([]byte, error) { 96 | bound := CompressBound(len(src)) 97 | if cap(dst) >= bound { 98 | dst = dst[0:bound] // Reuse dst buffer 99 | } else { 100 | dst = make([]byte, bound) 101 | } 102 | 103 | // We need unsafe.Pointer(&src[0]) in the Cgo call to avoid "Go pointer to Go pointer" panics. 104 | // This means we need to special case empty input. See: 105 | // https://github.com/golang/go/issues/14210#issuecomment-346402945 106 | var cWritten C.size_t 107 | if len(src) == 0 { 108 | cWritten = C.ZSTD_compress( 109 | unsafe.Pointer(&dst[0]), 110 | C.size_t(len(dst)), 111 | unsafe.Pointer(nil), 112 | C.size_t(0), 113 | C.int(level)) 114 | } else { 115 | cWritten = C.ZSTD_compress( 116 | unsafe.Pointer(&dst[0]), 117 | C.size_t(len(dst)), 118 | unsafe.Pointer(&src[0]), 119 | C.size_t(len(src)), 120 | C.int(level)) 121 | } 122 | 123 | written := int(cWritten) 124 | // Check if the return is an Error code 125 | if err := getError(written); err != nil { 126 | return nil, err 127 | } 128 | return dst[:written], nil 129 | } 130 | 131 | // Decompress src into dst. If you have a buffer to use, you can pass it to 132 | // prevent allocation. If it is too small, or if nil is passed, a new buffer 133 | // will be allocated and returned. 134 | func Decompress(dst, src []byte) ([]byte, error) { 135 | if len(src) == 0 { 136 | return []byte{}, ErrEmptySlice 137 | } 138 | 139 | bound := decompressSizeHint(src) 140 | if cap(dst) >= bound { 141 | dst = dst[0:cap(dst)] 142 | } else { 143 | dst = make([]byte, bound) 144 | } 145 | 146 | written, err := DecompressInto(dst, src) 147 | if err == nil { 148 | return dst[:written], nil 149 | } 150 | if !IsDstSizeTooSmallError(err) { 151 | return nil, err 152 | } 153 | 154 | // We failed getting a dst buffer of correct size, use stream API 155 | r := NewReader(bytes.NewReader(src)) 156 | defer r.Close() 157 | return ioutil.ReadAll(r) 158 | } 159 | 160 | // DecompressInto decompresses src into dst. Unlike Decompress, DecompressInto 161 | // requires that dst be sufficiently large to hold the decompressed payload. 162 | // DecompressInto may be used when the caller knows the size of the decompressed 163 | // payload before attempting decompression. 164 | // 165 | // It returns the number of bytes copied and an error if any is encountered. If 166 | // dst is too small, DecompressInto errors. 167 | func DecompressInto(dst, src []byte) (int, error) { 168 | written := int(C.ZSTD_decompress( 169 | unsafe.Pointer(&dst[0]), 170 | C.size_t(len(dst)), 171 | unsafe.Pointer(&src[0]), 172 | C.size_t(len(src)))) 173 | return written, getError(written) 174 | } 175 | -------------------------------------------------------------------------------- /zstd_bulk.go: -------------------------------------------------------------------------------- 1 | package zstd 2 | 3 | /* 4 | #include "zstd.h" 5 | */ 6 | import "C" 7 | import ( 8 | "errors" 9 | "runtime" 10 | "unsafe" 11 | ) 12 | 13 | var ( 14 | // ErrEmptyDictionary is returned when the given dictionary is empty 15 | ErrEmptyDictionary = errors.New("Dictionary is empty") 16 | // ErrBadDictionary is returned when cannot load the given dictionary 17 | ErrBadDictionary = errors.New("Cannot load dictionary") 18 | ) 19 | 20 | // BulkProcessor implements Bulk processing dictionary API. 21 | // When compressing multiple messages or blocks using the same dictionary, 22 | // it's recommended to digest the dictionary only once, since it's a costly operation. 23 | // NewBulkProcessor() will create a state from digesting a dictionary. 24 | // The resulting state can be used for future compression/decompression operations with very limited startup cost. 25 | // BulkProcessor can be created once and shared by multiple threads concurrently, since its usage is read-only. 26 | // The state will be freed when gc cleans up BulkProcessor. 27 | type BulkProcessor struct { 28 | cDict *C.struct_ZSTD_CDict_s 29 | dDict *C.struct_ZSTD_DDict_s 30 | } 31 | 32 | // NewBulkProcessor creates a new BulkProcessor with a pre-trained dictionary and compression level 33 | func NewBulkProcessor(dictionary []byte, compressionLevel int) (*BulkProcessor, error) { 34 | if len(dictionary) < 1 { 35 | return nil, ErrEmptyDictionary 36 | } 37 | 38 | p := &BulkProcessor{} 39 | runtime.SetFinalizer(p, finalizeBulkProcessor) 40 | 41 | p.cDict = C.ZSTD_createCDict( 42 | unsafe.Pointer(&dictionary[0]), 43 | C.size_t(len(dictionary)), 44 | C.int(compressionLevel), 45 | ) 46 | if p.cDict == nil { 47 | return nil, ErrBadDictionary 48 | } 49 | p.dDict = C.ZSTD_createDDict( 50 | unsafe.Pointer(&dictionary[0]), 51 | C.size_t(len(dictionary)), 52 | ) 53 | if p.dDict == nil { 54 | return nil, ErrBadDictionary 55 | } 56 | 57 | return p, nil 58 | } 59 | 60 | // Compress compresses `src` into `dst` with the dictionary given when creating the BulkProcessor. 61 | // If you have a buffer to use, you can pass it to prevent allocation. 62 | // If it is too small, or if nil is passed, a new buffer will be allocated and returned. 63 | func (p *BulkProcessor) Compress(dst, src []byte) ([]byte, error) { 64 | bound := CompressBound(len(src)) 65 | if cap(dst) >= bound { 66 | dst = dst[0:bound] 67 | } else { 68 | dst = make([]byte, bound) 69 | } 70 | 71 | cctx := C.ZSTD_createCCtx() 72 | // We need unsafe.Pointer(&src[0]) in the Cgo call to avoid "Go pointer to Go pointer" panics. 73 | // This means we need to special case empty input. See: 74 | // https://github.com/golang/go/issues/14210#issuecomment-346402945 75 | var cWritten C.size_t 76 | if len(src) == 0 { 77 | cWritten = C.ZSTD_compress_usingCDict( 78 | cctx, 79 | unsafe.Pointer(&dst[0]), 80 | C.size_t(len(dst)), 81 | unsafe.Pointer(nil), 82 | C.size_t(len(src)), 83 | p.cDict, 84 | ) 85 | } else { 86 | cWritten = C.ZSTD_compress_usingCDict( 87 | cctx, 88 | unsafe.Pointer(&dst[0]), 89 | C.size_t(len(dst)), 90 | unsafe.Pointer(&src[0]), 91 | C.size_t(len(src)), 92 | p.cDict, 93 | ) 94 | } 95 | 96 | C.ZSTD_freeCCtx(cctx) 97 | 98 | written := int(cWritten) 99 | if err := getError(written); err != nil { 100 | return nil, err 101 | } 102 | return dst[:written], nil 103 | } 104 | 105 | // Decompress decompresses `src` into `dst` with the dictionary given when creating the BulkProcessor. 106 | // If you have a buffer to use, you can pass it to prevent allocation. 107 | // If it is too small, or if nil is passed, a new buffer will be allocated and returned. 108 | func (p *BulkProcessor) Decompress(dst, src []byte) ([]byte, error) { 109 | if len(src) == 0 { 110 | return nil, ErrEmptySlice 111 | } 112 | 113 | contentSize := decompressSizeHint(src) 114 | if cap(dst) >= contentSize { 115 | dst = dst[0:cap(dst)] 116 | } else { 117 | dst = make([]byte, contentSize) 118 | } 119 | 120 | if len(dst) == 0 { 121 | return dst, nil 122 | } 123 | 124 | dctx := C.ZSTD_createDCtx() 125 | cWritten := C.ZSTD_decompress_usingDDict( 126 | dctx, 127 | unsafe.Pointer(&dst[0]), 128 | C.size_t(len(dst)), 129 | unsafe.Pointer(&src[0]), 130 | C.size_t(len(src)), 131 | p.dDict, 132 | ) 133 | C.ZSTD_freeDCtx(dctx) 134 | 135 | written := int(cWritten) 136 | if err := getError(written); err != nil { 137 | return nil, err 138 | } 139 | 140 | return dst[:written], nil 141 | } 142 | 143 | // finalizeBulkProcessor frees compression and decompression dictionaries from memory 144 | func finalizeBulkProcessor(p *BulkProcessor) { 145 | if p.cDict != nil { 146 | C.ZSTD_freeCDict(p.cDict) 147 | } 148 | if p.dDict != nil { 149 | C.ZSTD_freeDDict(p.dDict) 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /zstd_bullk_test.go: -------------------------------------------------------------------------------- 1 | package zstd 2 | 3 | import ( 4 | "bytes" 5 | "encoding/base64" 6 | "math/rand" 7 | "regexp" 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | var dictBase64 string = ` 13 | N6Qw7IsuFDIdENCSQjr//////4+QlekuNkmXbUBIkIDiVRX7H4AzAFCgQCFCO9oHAAAEQEuSikaK 14 | Dg51OYghBYgBAAAAAAAAAAAAAAAAAAAAANQVpmRQGQAAAAAAAAAAAAAAAAABAAAABAAAAAgAAABo 15 | ZWxwIEpvaW4gZW5naW5lZXJzIGVuZ2luZWVycyBmdXR1cmUgbG92ZSB0aGF0IGFyZWlsZGluZyB1 16 | c2UgaGVscCBoZWxwIHVzaGVyIEpvaW4gdXNlIGxvdmUgdXMgSm9pbiB1bmQgaW4gdXNoZXIgdXNo 17 | ZXIgYSBwbGF0Zm9ybSB1c2UgYW5kIGZ1dHVyZQ==` 18 | var dict []byte 19 | var compressedPayload []byte 20 | 21 | func init() { 22 | var err error 23 | dict, err = base64.StdEncoding.DecodeString(regexp.MustCompile(`\s+`).ReplaceAllString(dictBase64, "")) 24 | if err != nil { 25 | panic("failed to create dictionary") 26 | } 27 | p, err := NewBulkProcessor(dict, BestSpeed) 28 | if err != nil { 29 | panic("failed to create bulk processor") 30 | } 31 | compressedPayload, err = p.Compress(nil, []byte("We're building a platform that engineers love to use. Join us, and help usher in the future.")) 32 | if err != nil { 33 | panic("failed to compress payload") 34 | } 35 | } 36 | 37 | func newBulkProcessor(t testing.TB, dict []byte, level int) *BulkProcessor { 38 | p, err := NewBulkProcessor(dict, level) 39 | if err != nil { 40 | t.Fatal("failed to create a BulkProcessor") 41 | } 42 | return p 43 | } 44 | 45 | func getRandomText() string { 46 | words := []string{"We", "are", "building", "a platform", "that", "engineers", "love", "to", "use", "Join", "us", "and", "help", "usher", "in", "the", "future"} 47 | wordCount := 10 + rand.Intn(100) // 10 - 109 48 | result := []string{} 49 | for i := 0; i < wordCount; i++ { 50 | result = append(result, words[rand.Intn(len(words))]) 51 | } 52 | 53 | return strings.Join(result, " ") 54 | } 55 | 56 | func TestBulkDictionary(t *testing.T) { 57 | if len(dict) < 1 { 58 | t.Error("dictionary is empty") 59 | } 60 | } 61 | 62 | func TestBulkCompressAndDecompress(t *testing.T) { 63 | p := newBulkProcessor(t, dict, BestSpeed) 64 | for i := 0; i < 100; i++ { 65 | payload := []byte(getRandomText()) 66 | 67 | compressed, err := p.Compress(nil, payload) 68 | if err != nil { 69 | t.Error("failed to compress") 70 | } 71 | 72 | uncompressed, err := p.Decompress(nil, compressed) 73 | if err != nil { 74 | t.Error("failed to decompress") 75 | } 76 | 77 | if bytes.Compare(payload, uncompressed) != 0 { 78 | t.Error("uncompressed payload didn't match") 79 | } 80 | } 81 | } 82 | 83 | func TestBulkEmptyOrNilDictionary(t *testing.T) { 84 | p, err := NewBulkProcessor(nil, BestSpeed) 85 | if p != nil { 86 | t.Error("nil is expected") 87 | } 88 | if err != ErrEmptyDictionary { 89 | t.Error("ErrEmptyDictionary is expected") 90 | } 91 | 92 | p, err = NewBulkProcessor([]byte{}, BestSpeed) 93 | if p != nil { 94 | t.Error("nil is expected") 95 | } 96 | if err != ErrEmptyDictionary { 97 | t.Error("ErrEmptyDictionary is expected") 98 | } 99 | } 100 | 101 | func TestBulkCompressDecompressEmptyOrNilContent(t *testing.T) { 102 | p := newBulkProcessor(t, dict, BestSpeed) 103 | compressed, err := p.Compress(nil, nil) 104 | if err != nil { 105 | t.Error("failed to compress") 106 | } 107 | if len(compressed) < 4 { 108 | t.Error("magic number doesn't exist") 109 | } 110 | 111 | compressed, err = p.Compress(nil, []byte{}) 112 | if err != nil { 113 | t.Error("failed to compress") 114 | } 115 | if len(compressed) < 4 { 116 | t.Error("magic number doesn't exist") 117 | } 118 | 119 | decompressed, err := p.Decompress(nil, compressed) 120 | if err != nil { 121 | t.Error("failed to decompress") 122 | } 123 | if len(decompressed) != 0 { 124 | t.Error("content was not decompressed correctly") 125 | } 126 | } 127 | 128 | func TestBulkCompressIntoGivenDestination(t *testing.T) { 129 | p := newBulkProcessor(t, dict, BestSpeed) 130 | dst := make([]byte, 100000) 131 | compressed, err := p.Compress(dst, []byte(getRandomText())) 132 | if err != nil { 133 | t.Error("failed to compress") 134 | } 135 | if len(compressed) < 4 { 136 | t.Error("magic number doesn't exist") 137 | } 138 | if &dst[0] != &compressed[0] { 139 | t.Error("'dst' and 'compressed' are not the same object") 140 | } 141 | } 142 | 143 | func TestBulkCompressNotEnoughDestination(t *testing.T) { 144 | p := newBulkProcessor(t, dict, BestSpeed) 145 | dst := make([]byte, 1) 146 | compressed, err := p.Compress(dst, []byte(getRandomText())) 147 | if err != nil { 148 | t.Error("failed to compress") 149 | } 150 | if len(compressed) < 4 { 151 | t.Error("magic number doesn't exist") 152 | } 153 | if &dst[0] == &compressed[0] { 154 | t.Error("'dst' and 'compressed' are the same object") 155 | } 156 | } 157 | 158 | func TestBulkDecompressIntoGivenDestination(t *testing.T) { 159 | p := newBulkProcessor(t, dict, BestSpeed) 160 | dst := make([]byte, 100000) 161 | decompressed, err := p.Decompress(dst, compressedPayload) 162 | if err != nil { 163 | t.Error("failed to decompress") 164 | } 165 | if &dst[0] != &decompressed[0] { 166 | t.Error("'dst' and 'decompressed' are not the same object") 167 | } 168 | } 169 | 170 | func TestBulkDecompressNotEnoughDestination(t *testing.T) { 171 | p := newBulkProcessor(t, dict, BestSpeed) 172 | dst := make([]byte, 1) 173 | decompressed, err := p.Decompress(dst, compressedPayload) 174 | if err != nil { 175 | t.Error("failed to decompress") 176 | } 177 | if &dst[0] == &decompressed[0] { 178 | t.Error("'dst' and 'decompressed' are the same object") 179 | } 180 | } 181 | 182 | func TestBulkDecompressEmptyOrNilContent(t *testing.T) { 183 | p := newBulkProcessor(t, dict, BestSpeed) 184 | decompressed, err := p.Decompress(nil, nil) 185 | if err != ErrEmptySlice { 186 | t.Error("ErrEmptySlice is expected") 187 | } 188 | if decompressed != nil { 189 | t.Error("nil is expected") 190 | } 191 | 192 | decompressed, err = p.Decompress(nil, []byte{}) 193 | if err != ErrEmptySlice { 194 | t.Error("ErrEmptySlice is expected") 195 | } 196 | if decompressed != nil { 197 | t.Error("nil is expected") 198 | } 199 | } 200 | 201 | func TestBulkCompressAndDecompressInReverseOrder(t *testing.T) { 202 | p := newBulkProcessor(t, dict, BestSpeed) 203 | payloads := [][]byte{} 204 | compressedPayloads := [][]byte{} 205 | for i := 0; i < 100; i++ { 206 | payloads = append(payloads, []byte(getRandomText())) 207 | 208 | compressed, err := p.Compress(nil, payloads[i]) 209 | if err != nil { 210 | t.Error("failed to compress") 211 | } 212 | compressedPayloads = append(compressedPayloads, compressed) 213 | } 214 | 215 | for i := 99; i >= 0; i-- { 216 | uncompressed, err := p.Decompress(nil, compressedPayloads[i]) 217 | if err != nil { 218 | t.Error("failed to decompress") 219 | } 220 | 221 | if bytes.Compare(payloads[i], uncompressed) != 0 { 222 | t.Error("uncompressed payload didn't match") 223 | } 224 | } 225 | } 226 | 227 | func TestBulkDecompressHighlyCompressable(t *testing.T) { 228 | p := newBulkProcessor(t, dict, BestSpeed) 229 | 230 | // Generate a big payload 231 | msgSize := 10 * 1000 * 1000 // 10 MiB 232 | msg := make([]byte, msgSize) 233 | compressed, err := Compress(nil, msg) 234 | if err != nil { 235 | t.Error("failed to compress") 236 | } 237 | 238 | // Regular decompression would trigger zipbomb prevention 239 | _, err = p.Decompress(nil, compressed) 240 | if !IsDstSizeTooSmallError(err) { 241 | t.Error("expected too small error") 242 | } 243 | 244 | // Passing an output should suceed the decompression 245 | dst := make([]byte, 10*msgSize) 246 | _, err = p.Decompress(dst, compressed) 247 | if err != nil { 248 | t.Errorf("failed to decompress: %s", err) 249 | } 250 | } 251 | 252 | // BenchmarkBulkCompress-8 780148 1505 ns/op 61.14 MB/s 208 B/op 5 allocs/op 253 | func BenchmarkBulkCompress(b *testing.B) { 254 | p := newBulkProcessor(b, dict, BestSpeed) 255 | 256 | payload := []byte("We're building a platform that engineers love to use. Join us, and help usher in the future.") 257 | b.SetBytes(int64(len(payload))) 258 | for n := 0; n < b.N; n++ { 259 | _, err := p.Compress(nil, payload) 260 | if err != nil { 261 | b.Error("failed to compress") 262 | } 263 | } 264 | } 265 | 266 | // BenchmarkBulkDecompress-8 817425 1412 ns/op 40.37 MB/s 192 B/op 7 allocs/op 267 | func BenchmarkBulkDecompress(b *testing.B) { 268 | p := newBulkProcessor(b, dict, BestSpeed) 269 | 270 | b.SetBytes(int64(len(compressedPayload))) 271 | for n := 0; n < b.N; n++ { 272 | _, err := p.Decompress(nil, compressedPayload) 273 | if err != nil { 274 | b.Error("failed to decompress") 275 | } 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /zstd_common.c: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | 13 | 14 | /*-************************************* 15 | * Dependencies 16 | ***************************************/ 17 | #define ZSTD_DEPS_NEED_MALLOC 18 | #include "error_private.h" 19 | #include "zstd_internal.h" 20 | 21 | 22 | /*-**************************************** 23 | * Version 24 | ******************************************/ 25 | unsigned ZSTD_versionNumber(void) { return ZSTD_VERSION_NUMBER; } 26 | 27 | const char* ZSTD_versionString(void) { return ZSTD_VERSION_STRING; } 28 | 29 | 30 | /*-**************************************** 31 | * ZSTD Error Management 32 | ******************************************/ 33 | #undef ZSTD_isError /* defined within zstd_internal.h */ 34 | /*! ZSTD_isError() : 35 | * tells if a return value is an error code 36 | * symbol is required for external callers */ 37 | unsigned ZSTD_isError(size_t code) { return ERR_isError(code); } 38 | 39 | /*! ZSTD_getErrorName() : 40 | * provides error code string from function result (useful for debugging) */ 41 | const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); } 42 | 43 | /*! ZSTD_getError() : 44 | * convert a `size_t` function result into a proper ZSTD_errorCode enum */ 45 | ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); } 46 | 47 | /*! ZSTD_getErrorString() : 48 | * provides error code string from enum */ 49 | const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); } 50 | 51 | #endif /* USE_EXTERNAL_ZSTD */ 52 | -------------------------------------------------------------------------------- /zstd_compress_literals.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_COMPRESS_LITERALS_H 13 | #define ZSTD_COMPRESS_LITERALS_H 14 | 15 | #include "zstd_compress_internal.h" /* ZSTD_hufCTables_t, ZSTD_minGain() */ 16 | 17 | 18 | size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize); 19 | 20 | /* ZSTD_compressRleLiteralsBlock() : 21 | * Conditions : 22 | * - All bytes in @src are identical 23 | * - dstCapacity >= 4 */ 24 | size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize); 25 | 26 | /* ZSTD_compressLiterals(): 27 | * @entropyWorkspace: must be aligned on 4-bytes boundaries 28 | * @entropyWorkspaceSize : must be >= HUF_WORKSPACE_SIZE 29 | * @suspectUncompressible: sampling checks, to potentially skip huffman coding 30 | */ 31 | size_t ZSTD_compressLiterals (void* dst, size_t dstCapacity, 32 | const void* src, size_t srcSize, 33 | void* entropyWorkspace, size_t entropyWorkspaceSize, 34 | const ZSTD_hufCTables_t* prevHuf, 35 | ZSTD_hufCTables_t* nextHuf, 36 | ZSTD_strategy strategy, int disableLiteralCompression, 37 | int suspectUncompressible, 38 | int bmi2); 39 | 40 | #endif /* ZSTD_COMPRESS_LITERALS_H */ 41 | 42 | #endif /* USE_EXTERNAL_ZSTD */ 43 | -------------------------------------------------------------------------------- /zstd_compress_sequences.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_COMPRESS_SEQUENCES_H 13 | #define ZSTD_COMPRESS_SEQUENCES_H 14 | 15 | #include "zstd_compress_internal.h" /* SeqDef */ 16 | #include "fse.h" /* FSE_repeat, FSE_CTable */ 17 | #include "zstd_internal.h" /* SymbolEncodingType_e, ZSTD_strategy */ 18 | 19 | typedef enum { 20 | ZSTD_defaultDisallowed = 0, 21 | ZSTD_defaultAllowed = 1 22 | } ZSTD_DefaultPolicy_e; 23 | 24 | SymbolEncodingType_e 25 | ZSTD_selectEncodingType( 26 | FSE_repeat* repeatMode, unsigned const* count, unsigned const max, 27 | size_t const mostFrequent, size_t nbSeq, unsigned const FSELog, 28 | FSE_CTable const* prevCTable, 29 | short const* defaultNorm, U32 defaultNormLog, 30 | ZSTD_DefaultPolicy_e const isDefaultAllowed, 31 | ZSTD_strategy const strategy); 32 | 33 | size_t 34 | ZSTD_buildCTable(void* dst, size_t dstCapacity, 35 | FSE_CTable* nextCTable, U32 FSELog, SymbolEncodingType_e type, 36 | unsigned* count, U32 max, 37 | const BYTE* codeTable, size_t nbSeq, 38 | const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax, 39 | const FSE_CTable* prevCTable, size_t prevCTableSize, 40 | void* entropyWorkspace, size_t entropyWorkspaceSize); 41 | 42 | size_t ZSTD_encodeSequences( 43 | void* dst, size_t dstCapacity, 44 | FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, 45 | FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, 46 | FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, 47 | SeqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2); 48 | 49 | size_t ZSTD_fseBitCost( 50 | FSE_CTable const* ctable, 51 | unsigned const* count, 52 | unsigned const max); 53 | 54 | size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog, 55 | unsigned const* count, unsigned const max); 56 | #endif /* ZSTD_COMPRESS_SEQUENCES_H */ 57 | 58 | #endif /* USE_EXTERNAL_ZSTD */ 59 | -------------------------------------------------------------------------------- /zstd_compress_superblock.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_COMPRESS_ADVANCED_H 13 | #define ZSTD_COMPRESS_ADVANCED_H 14 | 15 | /*-************************************* 16 | * Dependencies 17 | ***************************************/ 18 | 19 | #include "zstd.h" /* ZSTD_CCtx */ 20 | 21 | /*-************************************* 22 | * Target Compressed Block Size 23 | ***************************************/ 24 | 25 | /* ZSTD_compressSuperBlock() : 26 | * Used to compress a super block when targetCBlockSize is being used. 27 | * The given block will be compressed into multiple sub blocks that are around targetCBlockSize. */ 28 | size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc, 29 | void* dst, size_t dstCapacity, 30 | void const* src, size_t srcSize, 31 | unsigned lastBlock); 32 | 33 | #endif /* ZSTD_COMPRESS_ADVANCED_H */ 34 | 35 | #endif /* USE_EXTERNAL_ZSTD */ 36 | -------------------------------------------------------------------------------- /zstd_ctx.go: -------------------------------------------------------------------------------- 1 | package zstd 2 | 3 | /* 4 | #include "zstd.h" 5 | */ 6 | import "C" 7 | import ( 8 | "bytes" 9 | "io/ioutil" 10 | "runtime" 11 | "unsafe" 12 | ) 13 | 14 | type Ctx interface { 15 | // Compress src into dst. If you have a buffer to use, you can pass it to 16 | // prevent allocation. If it is too small, or if nil is passed, a new buffer 17 | // will be allocated and returned. 18 | Compress(dst, src []byte) ([]byte, error) 19 | 20 | // CompressLevel is the same as Compress but you can pass a compression level 21 | CompressLevel(dst, src []byte, level int) ([]byte, error) 22 | 23 | // Decompress src into dst. If you have a buffer to use, you can pass it to 24 | // prevent allocation. If it is too small, or if nil is passed, a new buffer 25 | // will be allocated and returned. 26 | Decompress(dst, src []byte) ([]byte, error) 27 | 28 | // DecompressInto decompresses src into dst. Unlike Decompress, DecompressInto 29 | // requires that dst be sufficiently large to hold the decompressed payload. 30 | // DecompressInto may be used when the caller knows the size of the decompressed 31 | // payload before attempting decompression. 32 | // 33 | // It returns the number of bytes copied and an error if any is encountered. If 34 | // dst is too small, DecompressInto errors. 35 | DecompressInto(dst, src []byte) (int, error) 36 | } 37 | 38 | type ctx struct { 39 | cctx *C.ZSTD_CCtx 40 | dctx *C.ZSTD_DCtx 41 | } 42 | 43 | // Create a new ZStd Context. 44 | // When compressing/decompressing many times, it is recommended to allocate a 45 | // context just once, and re-use it for each successive compression operation. 46 | // This will make workload friendlier for system's memory. 47 | // Note : re-using context is just a speed / resource optimization. 48 | // It doesn't change the compression ratio, which remains identical. 49 | // Note 2 : In multi-threaded environments, 50 | // use one different context per thread for parallel execution. 51 | // 52 | func NewCtx() Ctx { 53 | c := &ctx{ 54 | cctx: C.ZSTD_createCCtx(), 55 | dctx: C.ZSTD_createDCtx(), 56 | } 57 | 58 | runtime.SetFinalizer(c, finalizeCtx) 59 | return c 60 | } 61 | 62 | func (c *ctx) Compress(dst, src []byte) ([]byte, error) { 63 | return c.CompressLevel(dst, src, DefaultCompression) 64 | } 65 | 66 | func (c *ctx) CompressLevel(dst, src []byte, level int) ([]byte, error) { 67 | bound := CompressBound(len(src)) 68 | if cap(dst) >= bound { 69 | dst = dst[0:bound] // Reuse dst buffer 70 | } else { 71 | dst = make([]byte, bound) 72 | } 73 | 74 | // We need unsafe.Pointer(&src[0]) in the Cgo call to avoid "Go pointer to Go pointer" panics. 75 | // This means we need to special case empty input. See: 76 | // https://github.com/golang/go/issues/14210#issuecomment-346402945 77 | var cWritten C.size_t 78 | if len(src) == 0 { 79 | cWritten = C.ZSTD_compressCCtx( 80 | c.cctx, 81 | unsafe.Pointer(&dst[0]), 82 | C.size_t(len(dst)), 83 | unsafe.Pointer(nil), 84 | C.size_t(0), 85 | C.int(level)) 86 | } else { 87 | cWritten = C.ZSTD_compressCCtx( 88 | c.cctx, 89 | unsafe.Pointer(&dst[0]), 90 | C.size_t(len(dst)), 91 | unsafe.Pointer(&src[0]), 92 | C.size_t(len(src)), 93 | C.int(level)) 94 | } 95 | 96 | written := int(cWritten) 97 | // Check if the return is an Error code 98 | if err := getError(written); err != nil { 99 | return nil, err 100 | } 101 | return dst[:written], nil 102 | } 103 | 104 | func (c *ctx) Decompress(dst, src []byte) ([]byte, error) { 105 | if len(src) == 0 { 106 | return []byte{}, ErrEmptySlice 107 | } 108 | 109 | bound := decompressSizeHint(src) 110 | if cap(dst) >= bound { 111 | dst = dst[0:cap(dst)] 112 | } else { 113 | dst = make([]byte, bound) 114 | } 115 | 116 | written, err := c.DecompressInto(dst, src) 117 | if err == nil { 118 | return dst[:written], nil 119 | } 120 | if !IsDstSizeTooSmallError(err) { 121 | return nil, err 122 | } 123 | 124 | // We failed getting a dst buffer of correct size, use stream API 125 | r := NewReader(bytes.NewReader(src)) 126 | defer r.Close() 127 | return ioutil.ReadAll(r) 128 | } 129 | 130 | func (c *ctx) DecompressInto(dst, src []byte) (int, error) { 131 | written := int(C.ZSTD_decompressDCtx( 132 | c.dctx, 133 | unsafe.Pointer(&dst[0]), 134 | C.size_t(len(dst)), 135 | unsafe.Pointer(&src[0]), 136 | C.size_t(len(src)))) 137 | err := getError(written) 138 | return written, err 139 | } 140 | 141 | func finalizeCtx(c *ctx) { 142 | C.ZSTD_freeCCtx(c.cctx) 143 | C.ZSTD_freeDCtx(c.dctx) 144 | } 145 | -------------------------------------------------------------------------------- /zstd_ctx_test.go: -------------------------------------------------------------------------------- 1 | package zstd 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | // Test compression 9 | func TestCtxCompressDecompress(t *testing.T) { 10 | ctx := NewCtx() 11 | 12 | input := []byte("Hello World!") 13 | out, err := ctx.Compress(nil, input) 14 | if err != nil { 15 | t.Fatalf("Error while compressing: %v", err) 16 | } 17 | out2 := make([]byte, 1000) 18 | out2, err = ctx.Compress(out2, input) 19 | if err != nil { 20 | t.Fatalf("Error while compressing: %v", err) 21 | } 22 | t.Logf("Compressed: %v", out) 23 | 24 | rein, err := ctx.Decompress(nil, out) 25 | if err != nil { 26 | t.Fatalf("Error while decompressing: %v", err) 27 | } 28 | rein2 := make([]byte, 10) 29 | rein2, err = ctx.Decompress(rein2, out2) 30 | if err != nil { 31 | t.Fatalf("Error while decompressing: %v", err) 32 | } 33 | 34 | if string(input) != string(rein) { 35 | t.Fatalf("Cannot compress and decompress: %s != %s", input, rein) 36 | } 37 | if string(input) != string(rein2) { 38 | t.Fatalf("Cannot compress and decompress: %s != %s", input, rein) 39 | } 40 | } 41 | 42 | func TestCtxCompressLevel(t *testing.T) { 43 | inputs := [][]byte{ 44 | nil, {}, {0}, []byte("Hello World!"), 45 | } 46 | 47 | cctx := NewCtx() 48 | for _, input := range inputs { 49 | for level := BestSpeed; level <= BestCompression; level++ { 50 | out, err := cctx.CompressLevel(nil, input, level) 51 | if err != nil { 52 | t.Errorf("input=%#v level=%d CompressLevel failed err=%s", string(input), level, err.Error()) 53 | continue 54 | } 55 | 56 | orig, err := Decompress(nil, out) 57 | if err != nil { 58 | t.Errorf("input=%#v level=%d Decompress failed err=%s", string(input), level, err.Error()) 59 | continue 60 | } 61 | if !bytes.Equal(orig, input) { 62 | t.Errorf("input=%#v level=%d orig does not match: %#v", string(input), level, string(orig)) 63 | } 64 | } 65 | } 66 | } 67 | 68 | func TestCtxCompressLevelNoGoPointers(t *testing.T) { 69 | testCompressNoGoPointers(t, func(input []byte) ([]byte, error) { 70 | cctx := NewCtx() 71 | return cctx.CompressLevel(nil, input, BestSpeed) 72 | }) 73 | } 74 | 75 | func TestCtxEmptySliceCompress(t *testing.T) { 76 | ctx := NewCtx() 77 | 78 | compressed, err := ctx.Compress(nil, []byte{}) 79 | if err != nil { 80 | t.Fatalf("Error while compressing: %v", err) 81 | } 82 | t.Logf("Compressing empty slice gives 0x%x", compressed) 83 | decompressed, err := ctx.Decompress(nil, compressed) 84 | if err != nil { 85 | t.Fatalf("Error while compressing: %v", err) 86 | } 87 | if string(decompressed) != "" { 88 | t.Fatalf("Expected empty slice as decompressed, got %v instead", decompressed) 89 | } 90 | } 91 | 92 | func TestCtxEmptySliceDecompress(t *testing.T) { 93 | ctx := NewCtx() 94 | 95 | _, err := ctx.Decompress(nil, []byte{}) 96 | if err != ErrEmptySlice { 97 | t.Fatalf("Did not get the correct error: %s", err) 98 | } 99 | } 100 | 101 | func TestCtxDecompressZeroLengthBuf(t *testing.T) { 102 | ctx := NewCtx() 103 | 104 | input := []byte("Hello World!") 105 | out, err := ctx.Compress(nil, input) 106 | if err != nil { 107 | t.Fatalf("Error while compressing: %v", err) 108 | } 109 | 110 | buf := make([]byte, 0) 111 | decompressed, err := ctx.Decompress(buf, out) 112 | if err != nil { 113 | t.Fatalf("Error while decompressing: %v", err) 114 | } 115 | 116 | if res, exp := string(input), string(decompressed); res != exp { 117 | t.Fatalf("expected %s but decompressed to %s", exp, res) 118 | } 119 | } 120 | 121 | func TestCtxCompressDecompressInto(t *testing.T) { 122 | ctx := NewCtx() 123 | payload := []byte("Hello World!") 124 | compressed, err := ctx.Compress(make([]byte, CompressBound(len(payload))), payload) 125 | if err != nil { 126 | t.Fatalf("Error while compressing: %v", err) 127 | } 128 | t.Logf("Compressed: %v", compressed) 129 | 130 | // We know the size of the payload; construct a buffer that perfectly fits 131 | // the payload and use DecompressInto. 132 | decompressed := make([]byte, len(payload)) 133 | if n, err := ctx.DecompressInto(decompressed, compressed); err != nil { 134 | t.Fatalf("error while decompressing into buffer of size %d: %v", 135 | len(decompressed), err) 136 | } else if n != len(decompressed) { 137 | t.Errorf("Ctx.DecompressedInto = (%d, nil), want (%d, nil)", n, len(decompressed)) 138 | } 139 | if !bytes.Equal(payload, decompressed) { 140 | t.Fatalf("Ctx.DecompressInto(_, Ctx.Compress(_, %q)) yielded %q, want %q", payload, decompressed, payload) 141 | } 142 | 143 | // Ensure that decompressing into a buffer too small errors appropriately. 144 | smallBuffer := make([]byte, len(payload)-1) 145 | if _, err := ctx.DecompressInto(smallBuffer, compressed); !IsDstSizeTooSmallError(err) { 146 | t.Fatalf("Ctx.DecompressInto(<%d-sized buffer>, Ctx.Compress(_, %q)) = %v, want 'Destination buffer is too small'", 147 | len(smallBuffer), payload, err) 148 | } 149 | } 150 | 151 | func TestCtxTooSmall(t *testing.T) { 152 | ctx := NewCtx() 153 | 154 | var long bytes.Buffer 155 | for i := 0; i < 10000; i++ { 156 | long.Write([]byte("Hellow World!")) 157 | } 158 | input := long.Bytes() 159 | out, err := ctx.Compress(nil, input) 160 | if err != nil { 161 | t.Fatalf("Error while compressing: %v", err) 162 | } 163 | rein := make([]byte, 1) 164 | // This should switch to the decompression stream to handle too small dst 165 | rein, err = ctx.Decompress(rein, out) 166 | if err != nil { 167 | t.Fatalf("Failed decompressing: %s", err) 168 | } 169 | if string(input) != string(rein) { 170 | t.Fatalf("Cannot compress and decompress: %s != %s", input, rein) 171 | } 172 | } 173 | 174 | func TestCtxRealPayload(t *testing.T) { 175 | ctx := NewCtx() 176 | 177 | if raw == nil { 178 | t.Skip(ErrNoPayloadEnv) 179 | } 180 | dst, err := ctx.Compress(nil, raw) 181 | if err != nil { 182 | t.Fatalf("Failed to compress: %s", err) 183 | } 184 | rein, err := ctx.Decompress(nil, dst) 185 | if err != nil { 186 | t.Fatalf("Failed to decompress: %s", err) 187 | } 188 | if string(raw) != string(rein) { 189 | t.Fatalf("compressed/decompressed payloads are not the same (lengths: %v & %v)", len(raw), len(rein)) 190 | } 191 | } 192 | 193 | func BenchmarkCtxCompression(b *testing.B) { 194 | ctx := NewCtx() 195 | 196 | if raw == nil { 197 | b.Fatal(ErrNoPayloadEnv) 198 | } 199 | dst := make([]byte, CompressBound(len(raw))) 200 | b.SetBytes(int64(len(raw))) 201 | b.ResetTimer() 202 | for i := 0; i < b.N; i++ { 203 | _, err := ctx.Compress(dst, raw) 204 | if err != nil { 205 | b.Fatalf("Failed compressing: %s", err) 206 | } 207 | } 208 | } 209 | 210 | func BenchmarkCtxDecompression(b *testing.B) { 211 | ctx := NewCtx() 212 | 213 | if raw == nil { 214 | b.Fatal(ErrNoPayloadEnv) 215 | } 216 | src := make([]byte, len(raw)) 217 | dst, err := ctx.Compress(nil, raw) 218 | if err != nil { 219 | b.Fatalf("Failed compressing: %s", err) 220 | } 221 | b.Logf("Reduced from %v to %v", len(raw), len(dst)) 222 | b.SetBytes(int64(len(raw))) 223 | b.ResetTimer() 224 | for i := 0; i < b.N; i++ { 225 | src2, err := ctx.Decompress(src, dst) 226 | if err != nil { 227 | b.Fatalf("Failed decompressing: %s", err) 228 | } 229 | b.StopTimer() 230 | if !bytes.Equal(raw, src2) { 231 | b.Fatalf("Results are not the same: %v != %v", len(raw), len(src2)) 232 | } 233 | b.StartTimer() 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /zstd_ddict.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | 13 | #ifndef ZSTD_DDICT_H 14 | #define ZSTD_DDICT_H 15 | 16 | /*-******************************************************* 17 | * Dependencies 18 | *********************************************************/ 19 | #include "zstd_deps.h" /* size_t */ 20 | #include "zstd.h" /* ZSTD_DDict, and several public functions */ 21 | 22 | 23 | /*-******************************************************* 24 | * Interface 25 | *********************************************************/ 26 | 27 | /* note: several prototypes are already published in `zstd.h` : 28 | * ZSTD_createDDict() 29 | * ZSTD_createDDict_byReference() 30 | * ZSTD_createDDict_advanced() 31 | * ZSTD_freeDDict() 32 | * ZSTD_initStaticDDict() 33 | * ZSTD_sizeof_DDict() 34 | * ZSTD_estimateDDictSize() 35 | * ZSTD_getDictID_fromDict() 36 | */ 37 | 38 | const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict); 39 | size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict); 40 | 41 | void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); 42 | 43 | 44 | 45 | #endif /* ZSTD_DDICT_H */ 46 | 47 | #endif /* USE_EXTERNAL_ZSTD */ 48 | -------------------------------------------------------------------------------- /zstd_decompress_block.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | 13 | #ifndef ZSTD_DEC_BLOCK_H 14 | #define ZSTD_DEC_BLOCK_H 15 | 16 | /*-******************************************************* 17 | * Dependencies 18 | *********************************************************/ 19 | #include "zstd_deps.h" /* size_t */ 20 | #include "zstd.h" /* DCtx, and some public functions */ 21 | #include "zstd_internal.h" /* blockProperties_t, and some public functions */ 22 | #include "zstd_decompress_internal.h" /* ZSTD_seqSymbol */ 23 | 24 | 25 | /* === Prototypes === */ 26 | 27 | /* note: prototypes already published within `zstd.h` : 28 | * ZSTD_decompressBlock() 29 | */ 30 | 31 | /* note: prototypes already published within `zstd_internal.h` : 32 | * ZSTD_getcBlockSize() 33 | * ZSTD_decodeSeqHeaders() 34 | */ 35 | 36 | 37 | /* Streaming state is used to inform allocation of the literal buffer */ 38 | typedef enum { 39 | not_streaming = 0, 40 | is_streaming = 1 41 | } streaming_operation; 42 | 43 | /* ZSTD_decompressBlock_internal() : 44 | * decompress block, starting at `src`, 45 | * into destination buffer `dst`. 46 | * @return : decompressed block size, 47 | * or an error code (which can be tested using ZSTD_isError()) 48 | */ 49 | size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, 50 | void* dst, size_t dstCapacity, 51 | const void* src, size_t srcSize, const streaming_operation streaming); 52 | 53 | /* ZSTD_buildFSETable() : 54 | * generate FSE decoding table for one symbol (ll, ml or off) 55 | * this function must be called with valid parameters only 56 | * (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.) 57 | * in which case it cannot fail. 58 | * The workspace must be 4-byte aligned and at least ZSTD_BUILD_FSE_TABLE_WKSP_SIZE bytes, which is 59 | * defined in zstd_decompress_internal.h. 60 | * Internal use only. 61 | */ 62 | void ZSTD_buildFSETable(ZSTD_seqSymbol* dt, 63 | const short* normalizedCounter, unsigned maxSymbolValue, 64 | const U32* baseValue, const U8* nbAdditionalBits, 65 | unsigned tableLog, void* wksp, size_t wkspSize, 66 | int bmi2); 67 | 68 | /* Internal definition of ZSTD_decompressBlock() to avoid deprecation warnings. */ 69 | size_t ZSTD_decompressBlock_deprecated(ZSTD_DCtx* dctx, 70 | void* dst, size_t dstCapacity, 71 | const void* src, size_t srcSize); 72 | 73 | 74 | #endif /* ZSTD_DEC_BLOCK_H */ 75 | 76 | #endif /* USE_EXTERNAL_ZSTD */ 77 | -------------------------------------------------------------------------------- /zstd_deps.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | /* This file provides common libc dependencies that zstd requires. 13 | * The purpose is to allow replacing this file with a custom implementation 14 | * to compile zstd without libc support. 15 | */ 16 | 17 | /* Need: 18 | * NULL 19 | * INT_MAX 20 | * UINT_MAX 21 | * ZSTD_memcpy() 22 | * ZSTD_memset() 23 | * ZSTD_memmove() 24 | */ 25 | #ifndef ZSTD_DEPS_COMMON 26 | #define ZSTD_DEPS_COMMON 27 | 28 | /* Even though we use qsort_r only for the dictionary builder, the macro 29 | * _GNU_SOURCE has to be declared *before* the inclusion of any standard 30 | * header and the script 'combine.sh' combines the whole zstd source code 31 | * in a single file. 32 | */ 33 | #if defined(__linux) || defined(__linux__) || defined(linux) || defined(__gnu_linux__) || \ 34 | defined(__CYGWIN__) || defined(__MSYS__) 35 | #if !defined(_GNU_SOURCE) && !defined(__ANDROID__) /* NDK doesn't ship qsort_r(). */ 36 | #define _GNU_SOURCE 37 | #endif 38 | #endif 39 | 40 | #include 41 | #include 42 | #include 43 | 44 | #if defined(__GNUC__) && __GNUC__ >= 4 45 | # define ZSTD_memcpy(d,s,l) __builtin_memcpy((d),(s),(l)) 46 | # define ZSTD_memmove(d,s,l) __builtin_memmove((d),(s),(l)) 47 | # define ZSTD_memset(p,v,l) __builtin_memset((p),(v),(l)) 48 | #else 49 | # define ZSTD_memcpy(d,s,l) memcpy((d),(s),(l)) 50 | # define ZSTD_memmove(d,s,l) memmove((d),(s),(l)) 51 | # define ZSTD_memset(p,v,l) memset((p),(v),(l)) 52 | #endif 53 | 54 | #endif /* ZSTD_DEPS_COMMON */ 55 | 56 | /* Need: 57 | * ZSTD_malloc() 58 | * ZSTD_free() 59 | * ZSTD_calloc() 60 | */ 61 | #ifdef ZSTD_DEPS_NEED_MALLOC 62 | #ifndef ZSTD_DEPS_MALLOC 63 | #define ZSTD_DEPS_MALLOC 64 | 65 | #include 66 | 67 | #define ZSTD_malloc(s) malloc(s) 68 | #define ZSTD_calloc(n,s) calloc((n), (s)) 69 | #define ZSTD_free(p) free((p)) 70 | 71 | #endif /* ZSTD_DEPS_MALLOC */ 72 | #endif /* ZSTD_DEPS_NEED_MALLOC */ 73 | 74 | /* 75 | * Provides 64-bit math support. 76 | * Need: 77 | * U64 ZSTD_div64(U64 dividend, U32 divisor) 78 | */ 79 | #ifdef ZSTD_DEPS_NEED_MATH64 80 | #ifndef ZSTD_DEPS_MATH64 81 | #define ZSTD_DEPS_MATH64 82 | 83 | #define ZSTD_div64(dividend, divisor) ((dividend) / (divisor)) 84 | 85 | #endif /* ZSTD_DEPS_MATH64 */ 86 | #endif /* ZSTD_DEPS_NEED_MATH64 */ 87 | 88 | /* Need: 89 | * assert() 90 | */ 91 | #ifdef ZSTD_DEPS_NEED_ASSERT 92 | #ifndef ZSTD_DEPS_ASSERT 93 | #define ZSTD_DEPS_ASSERT 94 | 95 | #include 96 | 97 | #endif /* ZSTD_DEPS_ASSERT */ 98 | #endif /* ZSTD_DEPS_NEED_ASSERT */ 99 | 100 | /* Need: 101 | * ZSTD_DEBUG_PRINT() 102 | */ 103 | #ifdef ZSTD_DEPS_NEED_IO 104 | #ifndef ZSTD_DEPS_IO 105 | #define ZSTD_DEPS_IO 106 | 107 | #include 108 | #define ZSTD_DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__) 109 | 110 | #endif /* ZSTD_DEPS_IO */ 111 | #endif /* ZSTD_DEPS_NEED_IO */ 112 | 113 | /* Only requested when is known to be present. 114 | * Need: 115 | * intptr_t 116 | */ 117 | #ifdef ZSTD_DEPS_NEED_STDINT 118 | #ifndef ZSTD_DEPS_STDINT 119 | #define ZSTD_DEPS_STDINT 120 | 121 | #include 122 | 123 | #endif /* ZSTD_DEPS_STDINT */ 124 | #endif /* ZSTD_DEPS_NEED_STDINT */ 125 | 126 | #endif /* USE_EXTERNAL_ZSTD */ 127 | -------------------------------------------------------------------------------- /zstd_double_fast.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_DOUBLE_FAST_H 13 | #define ZSTD_DOUBLE_FAST_H 14 | 15 | #include "mem.h" /* U32 */ 16 | #include "zstd_compress_internal.h" /* ZSTD_CCtx, size_t */ 17 | 18 | #ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR 19 | 20 | void ZSTD_fillDoubleHashTable(ZSTD_MatchState_t* ms, 21 | void const* end, ZSTD_dictTableLoadMethod_e dtlm, 22 | ZSTD_tableFillPurpose_e tfp); 23 | 24 | size_t ZSTD_compressBlock_doubleFast( 25 | ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 26 | void const* src, size_t srcSize); 27 | size_t ZSTD_compressBlock_doubleFast_dictMatchState( 28 | ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 29 | void const* src, size_t srcSize); 30 | size_t ZSTD_compressBlock_doubleFast_extDict( 31 | ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 32 | void const* src, size_t srcSize); 33 | 34 | #define ZSTD_COMPRESSBLOCK_DOUBLEFAST ZSTD_compressBlock_doubleFast 35 | #define ZSTD_COMPRESSBLOCK_DOUBLEFAST_DICTMATCHSTATE ZSTD_compressBlock_doubleFast_dictMatchState 36 | #define ZSTD_COMPRESSBLOCK_DOUBLEFAST_EXTDICT ZSTD_compressBlock_doubleFast_extDict 37 | #else 38 | #define ZSTD_COMPRESSBLOCK_DOUBLEFAST NULL 39 | #define ZSTD_COMPRESSBLOCK_DOUBLEFAST_DICTMATCHSTATE NULL 40 | #define ZSTD_COMPRESSBLOCK_DOUBLEFAST_EXTDICT NULL 41 | #endif /* ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR */ 42 | 43 | #endif /* ZSTD_DOUBLE_FAST_H */ 44 | 45 | #endif /* USE_EXTERNAL_ZSTD */ 46 | -------------------------------------------------------------------------------- /zstd_errors.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_ERRORS_H_398273423 13 | #define ZSTD_ERRORS_H_398273423 14 | 15 | #if defined (__cplusplus) 16 | extern "C" { 17 | #endif 18 | 19 | /* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */ 20 | #ifndef ZSTDERRORLIB_VISIBLE 21 | /* Backwards compatibility with old macro name */ 22 | # ifdef ZSTDERRORLIB_VISIBILITY 23 | # define ZSTDERRORLIB_VISIBLE ZSTDERRORLIB_VISIBILITY 24 | # elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) 25 | # define ZSTDERRORLIB_VISIBLE __attribute__ ((visibility ("default"))) 26 | # else 27 | # define ZSTDERRORLIB_VISIBLE 28 | # endif 29 | #endif 30 | 31 | #ifndef ZSTDERRORLIB_HIDDEN 32 | # if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) 33 | # define ZSTDERRORLIB_HIDDEN __attribute__ ((visibility ("hidden"))) 34 | # else 35 | # define ZSTDERRORLIB_HIDDEN 36 | # endif 37 | #endif 38 | 39 | #if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) 40 | # define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBLE 41 | #elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) 42 | # define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ 43 | #else 44 | # define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBLE 45 | #endif 46 | 47 | /*-********************************************* 48 | * Error codes list 49 | *-********************************************* 50 | * Error codes _values_ are pinned down since v1.3.1 only. 51 | * Therefore, don't rely on values if you may link to any version < v1.3.1. 52 | * 53 | * Only values < 100 are considered stable. 54 | * 55 | * note 1 : this API shall be used with static linking only. 56 | * dynamic linking is not yet officially supported. 57 | * note 2 : Prefer relying on the enum than on its value whenever possible 58 | * This is the only supported way to use the error list < v1.3.1 59 | * note 3 : ZSTD_isError() is always correct, whatever the library version. 60 | **********************************************/ 61 | typedef enum { 62 | ZSTD_error_no_error = 0, 63 | ZSTD_error_GENERIC = 1, 64 | ZSTD_error_prefix_unknown = 10, 65 | ZSTD_error_version_unsupported = 12, 66 | ZSTD_error_frameParameter_unsupported = 14, 67 | ZSTD_error_frameParameter_windowTooLarge = 16, 68 | ZSTD_error_corruption_detected = 20, 69 | ZSTD_error_checksum_wrong = 22, 70 | ZSTD_error_literals_headerWrong = 24, 71 | ZSTD_error_dictionary_corrupted = 30, 72 | ZSTD_error_dictionary_wrong = 32, 73 | ZSTD_error_dictionaryCreation_failed = 34, 74 | ZSTD_error_parameter_unsupported = 40, 75 | ZSTD_error_parameter_combination_unsupported = 41, 76 | ZSTD_error_parameter_outOfBound = 42, 77 | ZSTD_error_tableLog_tooLarge = 44, 78 | ZSTD_error_maxSymbolValue_tooLarge = 46, 79 | ZSTD_error_maxSymbolValue_tooSmall = 48, 80 | ZSTD_error_cannotProduce_uncompressedBlock = 49, 81 | ZSTD_error_stabilityCondition_notRespected = 50, 82 | ZSTD_error_stage_wrong = 60, 83 | ZSTD_error_init_missing = 62, 84 | ZSTD_error_memory_allocation = 64, 85 | ZSTD_error_workSpace_tooSmall= 66, 86 | ZSTD_error_dstSize_tooSmall = 70, 87 | ZSTD_error_srcSize_wrong = 72, 88 | ZSTD_error_dstBuffer_null = 74, 89 | ZSTD_error_noForwardProgress_destFull = 80, 90 | ZSTD_error_noForwardProgress_inputEmpty = 82, 91 | /* following error codes are __NOT STABLE__, they can be removed or changed in future versions */ 92 | ZSTD_error_frameIndex_tooLarge = 100, 93 | ZSTD_error_seekableIO = 102, 94 | ZSTD_error_dstBuffer_wrong = 104, 95 | ZSTD_error_srcBuffer_wrong = 105, 96 | ZSTD_error_sequenceProducer_failed = 106, 97 | ZSTD_error_externalSequences_invalid = 107, 98 | ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */ 99 | } ZSTD_ErrorCode; 100 | 101 | ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /**< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */ 102 | 103 | 104 | #if defined (__cplusplus) 105 | } 106 | #endif 107 | 108 | #endif /* ZSTD_ERRORS_H_398273423 */ 109 | 110 | #endif /* USE_EXTERNAL_ZSTD */ 111 | -------------------------------------------------------------------------------- /zstd_fast.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_FAST_H 13 | #define ZSTD_FAST_H 14 | 15 | #include "mem.h" /* U32 */ 16 | #include "zstd_compress_internal.h" 17 | 18 | void ZSTD_fillHashTable(ZSTD_MatchState_t* ms, 19 | void const* end, ZSTD_dictTableLoadMethod_e dtlm, 20 | ZSTD_tableFillPurpose_e tfp); 21 | size_t ZSTD_compressBlock_fast( 22 | ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 23 | void const* src, size_t srcSize); 24 | size_t ZSTD_compressBlock_fast_dictMatchState( 25 | ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 26 | void const* src, size_t srcSize); 27 | size_t ZSTD_compressBlock_fast_extDict( 28 | ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 29 | void const* src, size_t srcSize); 30 | 31 | #endif /* ZSTD_FAST_H */ 32 | 33 | #endif /* USE_EXTERNAL_ZSTD */ 34 | -------------------------------------------------------------------------------- /zstd_ldm.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_LDM_H 13 | #define ZSTD_LDM_H 14 | 15 | #include "zstd_compress_internal.h" /* ldmParams_t, U32 */ 16 | #include "zstd.h" /* ZSTD_CCtx, size_t */ 17 | 18 | /*-************************************* 19 | * Long distance matching 20 | ***************************************/ 21 | 22 | #define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_LIMIT_DEFAULT 23 | 24 | void ZSTD_ldm_fillHashTable( 25 | ldmState_t* state, const BYTE* ip, 26 | const BYTE* iend, ldmParams_t const* params); 27 | 28 | /** 29 | * ZSTD_ldm_generateSequences(): 30 | * 31 | * Generates the sequences using the long distance match finder. 32 | * Generates long range matching sequences in `sequences`, which parse a prefix 33 | * of the source. `sequences` must be large enough to store every sequence, 34 | * which can be checked with `ZSTD_ldm_getMaxNbSeq()`. 35 | * @returns 0 or an error code. 36 | * 37 | * NOTE: The user must have called ZSTD_window_update() for all of the input 38 | * they have, even if they pass it to ZSTD_ldm_generateSequences() in chunks. 39 | * NOTE: This function returns an error if it runs out of space to store 40 | * sequences. 41 | */ 42 | size_t ZSTD_ldm_generateSequences( 43 | ldmState_t* ldms, RawSeqStore_t* sequences, 44 | ldmParams_t const* params, void const* src, size_t srcSize); 45 | 46 | /** 47 | * ZSTD_ldm_blockCompress(): 48 | * 49 | * Compresses a block using the predefined sequences, along with a secondary 50 | * block compressor. The literals section of every sequence is passed to the 51 | * secondary block compressor, and those sequences are interspersed with the 52 | * predefined sequences. Returns the length of the last literals. 53 | * Updates `rawSeqStore.pos` to indicate how many sequences have been consumed. 54 | * `rawSeqStore.seq` may also be updated to split the last sequence between two 55 | * blocks. 56 | * @return The length of the last literals. 57 | * 58 | * NOTE: The source must be at most the maximum block size, but the predefined 59 | * sequences can be any size, and may be longer than the block. In the case that 60 | * they are longer than the block, the last sequences may need to be split into 61 | * two. We handle that case correctly, and update `rawSeqStore` appropriately. 62 | * NOTE: This function does not return any errors. 63 | */ 64 | size_t ZSTD_ldm_blockCompress(RawSeqStore_t* rawSeqStore, 65 | ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 66 | ZSTD_ParamSwitch_e useRowMatchFinder, 67 | void const* src, size_t srcSize); 68 | 69 | /** 70 | * ZSTD_ldm_skipSequences(): 71 | * 72 | * Skip past `srcSize` bytes worth of sequences in `rawSeqStore`. 73 | * Avoids emitting matches less than `minMatch` bytes. 74 | * Must be called for data that is not passed to ZSTD_ldm_blockCompress(). 75 | */ 76 | void ZSTD_ldm_skipSequences(RawSeqStore_t* rawSeqStore, size_t srcSize, 77 | U32 const minMatch); 78 | 79 | /* ZSTD_ldm_skipRawSeqStoreBytes(): 80 | * Moves forward in rawSeqStore by nbBytes, updating fields 'pos' and 'posInSequence'. 81 | * Not to be used in conjunction with ZSTD_ldm_skipSequences(). 82 | * Must be called for data with is not passed to ZSTD_ldm_blockCompress(). 83 | */ 84 | void ZSTD_ldm_skipRawSeqStoreBytes(RawSeqStore_t* rawSeqStore, size_t nbBytes); 85 | 86 | /** ZSTD_ldm_getTableSize() : 87 | * Estimate the space needed for long distance matching tables or 0 if LDM is 88 | * disabled. 89 | */ 90 | size_t ZSTD_ldm_getTableSize(ldmParams_t params); 91 | 92 | /** ZSTD_ldm_getSeqSpace() : 93 | * Return an upper bound on the number of sequences that can be produced by 94 | * the long distance matcher, or 0 if LDM is disabled. 95 | */ 96 | size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize); 97 | 98 | /** ZSTD_ldm_adjustParameters() : 99 | * If the params->hashRateLog is not set, set it to its default value based on 100 | * windowLog and params->hashLog. 101 | * 102 | * Ensures that params->bucketSizeLog is <= params->hashLog (setting it to 103 | * params->hashLog if it is not). 104 | * 105 | * Ensures that the minMatchLength >= targetLength during optimal parsing. 106 | */ 107 | void ZSTD_ldm_adjustParameters(ldmParams_t* params, 108 | ZSTD_compressionParameters const* cParams); 109 | 110 | #endif /* ZSTD_FAST_H */ 111 | 112 | #endif /* USE_EXTERNAL_ZSTD */ 113 | -------------------------------------------------------------------------------- /zstd_ldm_geartab.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_LDM_GEARTAB_H 13 | #define ZSTD_LDM_GEARTAB_H 14 | 15 | #include "compiler.h" /* UNUSED_ATTR */ 16 | #include "mem.h" /* U64 */ 17 | 18 | static UNUSED_ATTR const U64 ZSTD_ldm_gearTab[256] = { 19 | 0xf5b8f72c5f77775c, 0x84935f266b7ac412, 0xb647ada9ca730ccc, 20 | 0xb065bb4b114fb1de, 0x34584e7e8c3a9fd0, 0x4e97e17c6ae26b05, 21 | 0x3a03d743bc99a604, 0xcecd042422c4044f, 0x76de76c58524259e, 22 | 0x9c8528f65badeaca, 0x86563706e2097529, 0x2902475fa375d889, 23 | 0xafb32a9739a5ebe6, 0xce2714da3883e639, 0x21eaf821722e69e, 24 | 0x37b628620b628, 0x49a8d455d88caf5, 0x8556d711e6958140, 25 | 0x4f7ae74fc605c1f, 0x829f0c3468bd3a20, 0x4ffdc885c625179e, 26 | 0x8473de048a3daf1b, 0x51008822b05646b2, 0x69d75d12b2d1cc5f, 27 | 0x8c9d4a19159154bc, 0xc3cc10f4abbd4003, 0xd06ddc1cecb97391, 28 | 0xbe48e6e7ed80302e, 0x3481db31cee03547, 0xacc3f67cdaa1d210, 29 | 0x65cb771d8c7f96cc, 0x8eb27177055723dd, 0xc789950d44cd94be, 30 | 0x934feadc3700b12b, 0x5e485f11edbdf182, 0x1e2e2a46fd64767a, 31 | 0x2969ca71d82efa7c, 0x9d46e9935ebbba2e, 0xe056b67e05e6822b, 32 | 0x94d73f55739d03a0, 0xcd7010bdb69b5a03, 0x455ef9fcd79b82f4, 33 | 0x869cb54a8749c161, 0x38d1a4fa6185d225, 0xb475166f94bbe9bb, 34 | 0xa4143548720959f1, 0x7aed4780ba6b26ba, 0xd0ce264439e02312, 35 | 0x84366d746078d508, 0xa8ce973c72ed17be, 0x21c323a29a430b01, 36 | 0x9962d617e3af80ee, 0xab0ce91d9c8cf75b, 0x530e8ee6d19a4dbc, 37 | 0x2ef68c0cf53f5d72, 0xc03a681640a85506, 0x496e4e9f9c310967, 38 | 0x78580472b59b14a0, 0x273824c23b388577, 0x66bf923ad45cb553, 39 | 0x47ae1a5a2492ba86, 0x35e304569e229659, 0x4765182a46870b6f, 40 | 0x6cbab625e9099412, 0xddac9a2e598522c1, 0x7172086e666624f2, 41 | 0xdf5003ca503b7837, 0x88c0c1db78563d09, 0x58d51865acfc289d, 42 | 0x177671aec65224f1, 0xfb79d8a241e967d7, 0x2be1e101cad9a49a, 43 | 0x6625682f6e29186b, 0x399553457ac06e50, 0x35dffb4c23abb74, 44 | 0x429db2591f54aade, 0xc52802a8037d1009, 0x6acb27381f0b25f3, 45 | 0xf45e2551ee4f823b, 0x8b0ea2d99580c2f7, 0x3bed519cbcb4e1e1, 46 | 0xff452823dbb010a, 0x9d42ed614f3dd267, 0x5b9313c06257c57b, 47 | 0xa114b8008b5e1442, 0xc1fe311c11c13d4b, 0x66e8763ea34c5568, 48 | 0x8b982af1c262f05d, 0xee8876faaa75fbb7, 0x8a62a4d0d172bb2a, 49 | 0xc13d94a3b7449a97, 0x6dbbba9dc15d037c, 0xc786101f1d92e0f1, 50 | 0xd78681a907a0b79b, 0xf61aaf2962c9abb9, 0x2cfd16fcd3cb7ad9, 51 | 0x868c5b6744624d21, 0x25e650899c74ddd7, 0xba042af4a7c37463, 52 | 0x4eb1a539465a3eca, 0xbe09dbf03b05d5ca, 0x774e5a362b5472ba, 53 | 0x47a1221229d183cd, 0x504b0ca18ef5a2df, 0xdffbdfbde2456eb9, 54 | 0x46cd2b2fbee34634, 0xf2aef8fe819d98c3, 0x357f5276d4599d61, 55 | 0x24a5483879c453e3, 0x88026889192b4b9, 0x28da96671782dbec, 56 | 0x4ef37c40588e9aaa, 0x8837b90651bc9fb3, 0xc164f741d3f0e5d6, 57 | 0xbc135a0a704b70ba, 0x69cd868f7622ada, 0xbc37ba89e0b9c0ab, 58 | 0x47c14a01323552f6, 0x4f00794bacee98bb, 0x7107de7d637a69d5, 59 | 0x88af793bb6f2255e, 0xf3c6466b8799b598, 0xc288c616aa7f3b59, 60 | 0x81ca63cf42fca3fd, 0x88d85ace36a2674b, 0xd056bd3792389e7, 61 | 0xe55c396c4e9dd32d, 0xbefb504571e6c0a6, 0x96ab32115e91e8cc, 62 | 0xbf8acb18de8f38d1, 0x66dae58801672606, 0x833b6017872317fb, 63 | 0xb87c16f2d1c92864, 0xdb766a74e58b669c, 0x89659f85c61417be, 64 | 0xc8daad856011ea0c, 0x76a4b565b6fe7eae, 0xa469d085f6237312, 65 | 0xaaf0365683a3e96c, 0x4dbb746f8424f7b8, 0x638755af4e4acc1, 66 | 0x3d7807f5bde64486, 0x17be6d8f5bbb7639, 0x903f0cd44dc35dc, 67 | 0x67b672eafdf1196c, 0xa676ff93ed4c82f1, 0x521d1004c5053d9d, 68 | 0x37ba9ad09ccc9202, 0x84e54d297aacfb51, 0xa0b4b776a143445, 69 | 0x820d471e20b348e, 0x1874383cb83d46dc, 0x97edeec7a1efe11c, 70 | 0xb330e50b1bdc42aa, 0x1dd91955ce70e032, 0xa514cdb88f2939d5, 71 | 0x2791233fd90db9d3, 0x7b670a4cc50f7a9b, 0x77c07d2a05c6dfa5, 72 | 0xe3778b6646d0a6fa, 0xb39c8eda47b56749, 0x933ed448addbef28, 73 | 0xaf846af6ab7d0bf4, 0xe5af208eb666e49, 0x5e6622f73534cd6a, 74 | 0x297daeca42ef5b6e, 0x862daef3d35539a6, 0xe68722498f8e1ea9, 75 | 0x981c53093dc0d572, 0xfa09b0bfbf86fbf5, 0x30b1e96166219f15, 76 | 0x70e7d466bdc4fb83, 0x5a66736e35f2a8e9, 0xcddb59d2b7c1baef, 77 | 0xd6c7d247d26d8996, 0xea4e39eac8de1ba3, 0x539c8bb19fa3aff2, 78 | 0x9f90e4c5fd508d8, 0xa34e5956fbaf3385, 0x2e2f8e151d3ef375, 79 | 0x173691e9b83faec1, 0xb85a8d56bf016379, 0x8382381267408ae3, 80 | 0xb90f901bbdc0096d, 0x7c6ad32933bcec65, 0x76bb5e2f2c8ad595, 81 | 0x390f851a6cf46d28, 0xc3e6064da1c2da72, 0xc52a0c101cfa5389, 82 | 0xd78eaf84a3fbc530, 0x3781b9e2288b997e, 0x73c2f6dea83d05c4, 83 | 0x4228e364c5b5ed7, 0x9d7a3edf0da43911, 0x8edcfeda24686756, 84 | 0x5e7667a7b7a9b3a1, 0x4c4f389fa143791d, 0xb08bc1023da7cddc, 85 | 0x7ab4be3ae529b1cc, 0x754e6132dbe74ff9, 0x71635442a839df45, 86 | 0x2f6fb1643fbe52de, 0x961e0a42cf7a8177, 0xf3b45d83d89ef2ea, 87 | 0xee3de4cf4a6e3e9b, 0xcd6848542c3295e7, 0xe4cee1664c78662f, 88 | 0x9947548b474c68c4, 0x25d73777a5ed8b0b, 0xc915b1d636b7fc, 89 | 0x21c2ba75d9b0d2da, 0x5f6b5dcf608a64a1, 0xdcf333255ff9570c, 90 | 0x633b922418ced4ee, 0xc136dde0b004b34a, 0x58cc83b05d4b2f5a, 91 | 0x5eb424dda28e42d2, 0x62df47369739cd98, 0xb4e0b42485e4ce17, 92 | 0x16e1f0c1f9a8d1e7, 0x8ec3916707560ebf, 0x62ba6e2df2cc9db3, 93 | 0xcbf9f4ff77d83a16, 0x78d9d7d07d2bbcc4, 0xef554ce1e02c41f4, 94 | 0x8d7581127eccf94d, 0xa9b53336cb3c8a05, 0x38c42c0bf45c4f91, 95 | 0x640893cdf4488863, 0x80ec34bc575ea568, 0x39f324f5b48eaa40, 96 | 0xe9d9ed1f8eff527f, 0x9224fc058cc5a214, 0xbaba00b04cfe7741, 97 | 0x309a9f120fcf52af, 0xa558f3ec65626212, 0x424bec8b7adabe2f, 98 | 0x41622513a6aea433, 0xb88da2d5324ca798, 0xd287733b245528a4, 99 | 0x9a44697e6d68aec3, 0x7b1093be2f49bb28, 0x50bbec632e3d8aad, 100 | 0x6cd90723e1ea8283, 0x897b9e7431b02bf3, 0x219efdcb338a7047, 101 | 0x3b0311f0a27c0656, 0xdb17bf91c0db96e7, 0x8cd4fd6b4e85a5b2, 102 | 0xfab071054ba6409d, 0x40d6fe831fa9dfd9, 0xaf358debad7d791e, 103 | 0xeb8d0e25a65e3e58, 0xbbcbd3df14e08580, 0xcf751f27ecdab2b, 104 | 0x2b4da14f2613d8f4 105 | }; 106 | 107 | #endif /* ZSTD_LDM_GEARTAB_H */ 108 | 109 | #endif /* USE_EXTERNAL_ZSTD */ 110 | -------------------------------------------------------------------------------- /zstd_opt.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_OPT_H 13 | #define ZSTD_OPT_H 14 | 15 | #include "zstd_compress_internal.h" 16 | 17 | #if !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \ 18 | || !defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \ 19 | || !defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR) 20 | /* used in ZSTD_loadDictionaryContent() */ 21 | void ZSTD_updateTree(ZSTD_MatchState_t* ms, const BYTE* ip, const BYTE* iend); 22 | #endif 23 | 24 | #ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR 25 | size_t ZSTD_compressBlock_btopt( 26 | ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 27 | void const* src, size_t srcSize); 28 | size_t ZSTD_compressBlock_btopt_dictMatchState( 29 | ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 30 | void const* src, size_t srcSize); 31 | size_t ZSTD_compressBlock_btopt_extDict( 32 | ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 33 | void const* src, size_t srcSize); 34 | 35 | #define ZSTD_COMPRESSBLOCK_BTOPT ZSTD_compressBlock_btopt 36 | #define ZSTD_COMPRESSBLOCK_BTOPT_DICTMATCHSTATE ZSTD_compressBlock_btopt_dictMatchState 37 | #define ZSTD_COMPRESSBLOCK_BTOPT_EXTDICT ZSTD_compressBlock_btopt_extDict 38 | #else 39 | #define ZSTD_COMPRESSBLOCK_BTOPT NULL 40 | #define ZSTD_COMPRESSBLOCK_BTOPT_DICTMATCHSTATE NULL 41 | #define ZSTD_COMPRESSBLOCK_BTOPT_EXTDICT NULL 42 | #endif 43 | 44 | #ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR 45 | size_t ZSTD_compressBlock_btultra( 46 | ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 47 | void const* src, size_t srcSize); 48 | size_t ZSTD_compressBlock_btultra_dictMatchState( 49 | ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 50 | void const* src, size_t srcSize); 51 | size_t ZSTD_compressBlock_btultra_extDict( 52 | ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 53 | void const* src, size_t srcSize); 54 | 55 | /* note : no btultra2 variant for extDict nor dictMatchState, 56 | * because btultra2 is not meant to work with dictionaries 57 | * and is only specific for the first block (no prefix) */ 58 | size_t ZSTD_compressBlock_btultra2( 59 | ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 60 | void const* src, size_t srcSize); 61 | 62 | #define ZSTD_COMPRESSBLOCK_BTULTRA ZSTD_compressBlock_btultra 63 | #define ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE ZSTD_compressBlock_btultra_dictMatchState 64 | #define ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT ZSTD_compressBlock_btultra_extDict 65 | #define ZSTD_COMPRESSBLOCK_BTULTRA2 ZSTD_compressBlock_btultra2 66 | #else 67 | #define ZSTD_COMPRESSBLOCK_BTULTRA NULL 68 | #define ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE NULL 69 | #define ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT NULL 70 | #define ZSTD_COMPRESSBLOCK_BTULTRA2 NULL 71 | #endif 72 | 73 | #endif /* ZSTD_OPT_H */ 74 | 75 | #endif /* USE_EXTERNAL_ZSTD */ 76 | -------------------------------------------------------------------------------- /zstd_preSplit.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_PRESPLIT_H 13 | #define ZSTD_PRESPLIT_H 14 | 15 | #include /* size_t */ 16 | 17 | #define ZSTD_SLIPBLOCK_WORKSPACESIZE 8208 18 | 19 | /* ZSTD_splitBlock(): 20 | * @level must be a value between 0 and 4. 21 | * higher levels spend more energy to detect block boundaries. 22 | * @workspace must be aligned for size_t. 23 | * @wkspSize must be at least >= ZSTD_SLIPBLOCK_WORKSPACESIZE 24 | * note: 25 | * For the time being, this function only accepts full 128 KB blocks. 26 | * Therefore, @blockSize must be == 128 KB. 27 | * While this could be extended to smaller sizes in the future, 28 | * it is not yet clear if this would be useful. TBD. 29 | */ 30 | size_t ZSTD_splitBlock(const void* blockStart, size_t blockSize, 31 | int level, 32 | void* workspace, size_t wkspSize); 33 | 34 | #endif /* ZSTD_PRESPLIT_H */ 35 | 36 | #endif /* USE_EXTERNAL_ZSTD */ 37 | -------------------------------------------------------------------------------- /zstd_small_stream_test.go: -------------------------------------------------------------------------------- 1 | package zstd 2 | 3 | import ( 4 | "bytes" 5 | "math/rand" 6 | "testing" 7 | ) 8 | 9 | func BenchmarkSmallWriteStreamCompression(b *testing.B) { 10 | randbs := func(n int) []byte { 11 | bs := make([]byte, n) 12 | r, err := rand.Read(bs) 13 | if err != nil { 14 | b.Fatalf("Failed to generate random bytes for benchmark: %v", err) 15 | } 16 | if r < n { 17 | b.Fatalf("Read %d bytes, less than requested %d", r, n) 18 | } 19 | return bs 20 | } 21 | 22 | count := func(n int) []byte { 23 | bs := make([]byte, n) 24 | for i := 0; i < n; i++ { 25 | bs[i] = byte(n % 255) 26 | } 27 | return bs 28 | } 29 | 30 | for _, tt := range []struct { 31 | name string 32 | rawgen func(n int) []byte 33 | }{ 34 | { 35 | name: "all-zeros", 36 | rawgen: func(n int) []byte { return make([]byte, n) }, 37 | }, 38 | { 39 | name: "count", 40 | rawgen: count, 41 | }, 42 | { 43 | name: "random", 44 | rawgen: randbs, 45 | }, 46 | } { 47 | b.Run(tt.name, func(b *testing.B) { 48 | raw := tt.rawgen(b.N) 49 | var intermediate bytes.Buffer 50 | w := NewWriter(&intermediate) 51 | b.SetBytes(1) 52 | b.ResetTimer() 53 | for i := 0; i < b.N; i++ { 54 | _, err := w.Write(raw[i : i+1]) 55 | if err != nil { 56 | b.Fatalf("Failed writing to compress object: %s", err) 57 | } 58 | } 59 | w.Close() 60 | b.ReportMetric(float64(intermediate.Len())/float64(b.N), "compressed_bytes/op") 61 | }) 62 | 63 | } 64 | } 65 | 66 | func TestSmallWriteStreaming(t *testing.T) { 67 | b := &bytes.Buffer{} 68 | for i := 0; i < 5000; i++ { 69 | b.Write([]byte("Hello World! ")) 70 | } 71 | data1 := b.Bytes() 72 | 73 | // Compress 1 74 | buffer1 := &bytes.Buffer{} 75 | w1 := NewWriterLevel(buffer1, BestSpeed) 76 | _, err := w1.Write(data1) 77 | if err != nil { 78 | t.Fatalf("Failed to write data: %v", err) 79 | } 80 | err = w1.Close() 81 | if err != nil { 82 | t.Fatalf("Failed to close writer: %v", err) 83 | } 84 | 85 | // Compress 2 86 | buffer2 := &bytes.Buffer{} 87 | w2 := NewWriterLevel(buffer2, BestSpeed) 88 | for i := 0; i < 5000; i++ { 89 | _, err := w2.Write([]byte("Hello World! ")) 90 | if err != nil { 91 | t.Fatalf("Failed to write data: %v", err) 92 | } 93 | } 94 | err = w2.Close() 95 | if err != nil { 96 | t.Fatalf("Failed to close writer: %v", err) 97 | } 98 | 99 | if buffer1.Len() != buffer2.Len() { 100 | t.Errorf("expected unbuffered writes to use same amount of space as buffered writes.\n") 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /zstd_trace.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_TRACE_H 13 | #define ZSTD_TRACE_H 14 | 15 | #include 16 | 17 | /* weak symbol support 18 | * For now, enable conservatively: 19 | * - Only GNUC 20 | * - Only ELF 21 | * - Only x86-64, i386, aarch64 and risc-v. 22 | * Also, explicitly disable on platforms known not to work so they aren't 23 | * forgotten in the future. 24 | */ 25 | #if !defined(ZSTD_HAVE_WEAK_SYMBOLS) && \ 26 | defined(__GNUC__) && defined(__ELF__) && \ 27 | (defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \ 28 | defined(_M_IX86) || defined(__aarch64__) || defined(__riscv)) && \ 29 | !defined(__APPLE__) && !defined(_WIN32) && !defined(__MINGW32__) && \ 30 | !defined(__CYGWIN__) && !defined(_AIX) 31 | # define ZSTD_HAVE_WEAK_SYMBOLS 1 32 | #else 33 | # define ZSTD_HAVE_WEAK_SYMBOLS 0 34 | #endif 35 | #if ZSTD_HAVE_WEAK_SYMBOLS 36 | # define ZSTD_WEAK_ATTR __attribute__((__weak__)) 37 | #else 38 | # define ZSTD_WEAK_ATTR 39 | #endif 40 | 41 | /* Only enable tracing when weak symbols are available. */ 42 | #ifndef ZSTD_TRACE 43 | # define ZSTD_TRACE ZSTD_HAVE_WEAK_SYMBOLS 44 | #endif 45 | 46 | #if ZSTD_TRACE 47 | 48 | struct ZSTD_CCtx_s; 49 | struct ZSTD_DCtx_s; 50 | struct ZSTD_CCtx_params_s; 51 | 52 | typedef struct { 53 | /** 54 | * ZSTD_VERSION_NUMBER 55 | * 56 | * This is guaranteed to be the first member of ZSTD_trace. 57 | * Otherwise, this struct is not stable between versions. If 58 | * the version number does not match your expectation, you 59 | * should not interpret the rest of the struct. 60 | */ 61 | unsigned version; 62 | /** 63 | * Non-zero if streaming (de)compression is used. 64 | */ 65 | int streaming; 66 | /** 67 | * The dictionary ID. 68 | */ 69 | unsigned dictionaryID; 70 | /** 71 | * Is the dictionary cold? 72 | * Only set on decompression. 73 | */ 74 | int dictionaryIsCold; 75 | /** 76 | * The dictionary size or zero if no dictionary. 77 | */ 78 | size_t dictionarySize; 79 | /** 80 | * The uncompressed size of the data. 81 | */ 82 | size_t uncompressedSize; 83 | /** 84 | * The compressed size of the data. 85 | */ 86 | size_t compressedSize; 87 | /** 88 | * The fully resolved CCtx parameters (NULL on decompression). 89 | */ 90 | struct ZSTD_CCtx_params_s const* params; 91 | /** 92 | * The ZSTD_CCtx pointer (NULL on decompression). 93 | */ 94 | struct ZSTD_CCtx_s const* cctx; 95 | /** 96 | * The ZSTD_DCtx pointer (NULL on compression). 97 | */ 98 | struct ZSTD_DCtx_s const* dctx; 99 | } ZSTD_Trace; 100 | 101 | /** 102 | * A tracing context. It must be 0 when tracing is disabled. 103 | * Otherwise, any non-zero value returned by a tracing begin() 104 | * function is presented to any subsequent calls to end(). 105 | * 106 | * Any non-zero value is treated as tracing is enabled and not 107 | * interpreted by the library. 108 | * 109 | * Two possible uses are: 110 | * * A timestamp for when the begin() function was called. 111 | * * A unique key identifying the (de)compression, like the 112 | * address of the [dc]ctx pointer if you need to track 113 | * more information than just a timestamp. 114 | */ 115 | typedef unsigned long long ZSTD_TraceCtx; 116 | 117 | /** 118 | * Trace the beginning of a compression call. 119 | * @param cctx The dctx pointer for the compression. 120 | * It can be used as a key to map begin() to end(). 121 | * @returns Non-zero if tracing is enabled. The return value is 122 | * passed to ZSTD_trace_compress_end(). 123 | */ 124 | ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_compress_begin( 125 | struct ZSTD_CCtx_s const* cctx); 126 | 127 | /** 128 | * Trace the end of a compression call. 129 | * @param ctx The return value of ZSTD_trace_compress_begin(). 130 | * @param trace The zstd tracing info. 131 | */ 132 | ZSTD_WEAK_ATTR void ZSTD_trace_compress_end( 133 | ZSTD_TraceCtx ctx, 134 | ZSTD_Trace const* trace); 135 | 136 | /** 137 | * Trace the beginning of a decompression call. 138 | * @param dctx The dctx pointer for the decompression. 139 | * It can be used as a key to map begin() to end(). 140 | * @returns Non-zero if tracing is enabled. The return value is 141 | * passed to ZSTD_trace_compress_end(). 142 | */ 143 | ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_decompress_begin( 144 | struct ZSTD_DCtx_s const* dctx); 145 | 146 | /** 147 | * Trace the end of a decompression call. 148 | * @param ctx The return value of ZSTD_trace_decompress_begin(). 149 | * @param trace The zstd tracing info. 150 | */ 151 | ZSTD_WEAK_ATTR void ZSTD_trace_decompress_end( 152 | ZSTD_TraceCtx ctx, 153 | ZSTD_Trace const* trace); 154 | 155 | #endif /* ZSTD_TRACE */ 156 | 157 | #endif /* ZSTD_TRACE_H */ 158 | 159 | #endif /* USE_EXTERNAL_ZSTD */ 160 | -------------------------------------------------------------------------------- /zstd_v01.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_V01_H_28739879432 13 | #define ZSTD_V01_H_28739879432 14 | 15 | #if defined (__cplusplus) 16 | extern "C" { 17 | #endif 18 | 19 | /* ************************************* 20 | * Includes 21 | ***************************************/ 22 | #include /* size_t */ 23 | 24 | 25 | /* ************************************* 26 | * Simple one-step function 27 | ***************************************/ 28 | /** 29 | ZSTDv01_decompress() : decompress ZSTD frames compliant with v0.1.x format 30 | compressedSize : is the exact source size 31 | maxOriginalSize : is the size of the 'dst' buffer, which must be already allocated. 32 | It must be equal or larger than originalSize, otherwise decompression will fail. 33 | return : the number of bytes decompressed into destination buffer (originalSize) 34 | or an errorCode if it fails (which can be tested using ZSTDv01_isError()) 35 | */ 36 | size_t ZSTDv01_decompress( void* dst, size_t maxOriginalSize, 37 | const void* src, size_t compressedSize); 38 | 39 | /** 40 | ZSTDv01_findFrameSizeInfoLegacy() : get the source length and decompressed bound of a ZSTD frame compliant with v0.1.x format 41 | srcSize : The size of the 'src' buffer, at least as large as the frame pointed to by 'src' 42 | cSize (output parameter) : the number of bytes that would be read to decompress this frame 43 | or an error code if it fails (which can be tested using ZSTDv01_isError()) 44 | dBound (output parameter) : an upper-bound for the decompressed size of the data in the frame 45 | or ZSTD_CONTENTSIZE_ERROR if an error occurs 46 | 47 | note : assumes `cSize` and `dBound` are _not_ NULL. 48 | */ 49 | void ZSTDv01_findFrameSizeInfoLegacy(const void *src, size_t srcSize, 50 | size_t* cSize, unsigned long long* dBound); 51 | 52 | /** 53 | ZSTDv01_isError() : tells if the result of ZSTDv01_decompress() is an error 54 | */ 55 | unsigned ZSTDv01_isError(size_t code); 56 | 57 | 58 | /* ************************************* 59 | * Advanced functions 60 | ***************************************/ 61 | typedef struct ZSTDv01_Dctx_s ZSTDv01_Dctx; 62 | ZSTDv01_Dctx* ZSTDv01_createDCtx(void); 63 | size_t ZSTDv01_freeDCtx(ZSTDv01_Dctx* dctx); 64 | 65 | size_t ZSTDv01_decompressDCtx(void* ctx, 66 | void* dst, size_t maxOriginalSize, 67 | const void* src, size_t compressedSize); 68 | 69 | /* ************************************* 70 | * Streaming functions 71 | ***************************************/ 72 | size_t ZSTDv01_resetDCtx(ZSTDv01_Dctx* dctx); 73 | 74 | size_t ZSTDv01_nextSrcSizeToDecompress(ZSTDv01_Dctx* dctx); 75 | size_t ZSTDv01_decompressContinue(ZSTDv01_Dctx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize); 76 | /** 77 | Use above functions alternatively. 78 | ZSTD_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTD_decompressContinue(). 79 | ZSTD_decompressContinue() will use previous data blocks to improve compression if they are located prior to current block. 80 | Result is the number of bytes regenerated within 'dst'. 81 | It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some header. 82 | */ 83 | 84 | /* ************************************* 85 | * Prefix - version detection 86 | ***************************************/ 87 | #define ZSTDv01_magicNumber 0xFD2FB51E /* Big Endian version */ 88 | #define ZSTDv01_magicNumberLE 0x1EB52FFD /* Little Endian version */ 89 | 90 | 91 | #if defined (__cplusplus) 92 | } 93 | #endif 94 | 95 | #endif /* ZSTD_V01_H_28739879432 */ 96 | 97 | #endif /* USE_EXTERNAL_ZSTD */ 98 | -------------------------------------------------------------------------------- /zstd_v02.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_V02_H_4174539423 13 | #define ZSTD_V02_H_4174539423 14 | 15 | #if defined (__cplusplus) 16 | extern "C" { 17 | #endif 18 | 19 | /* ************************************* 20 | * Includes 21 | ***************************************/ 22 | #include /* size_t */ 23 | 24 | 25 | /* ************************************* 26 | * Simple one-step function 27 | ***************************************/ 28 | /** 29 | ZSTDv02_decompress() : decompress ZSTD frames compliant with v0.2.x format 30 | compressedSize : is the exact source size 31 | maxOriginalSize : is the size of the 'dst' buffer, which must be already allocated. 32 | It must be equal or larger than originalSize, otherwise decompression will fail. 33 | return : the number of bytes decompressed into destination buffer (originalSize) 34 | or an errorCode if it fails (which can be tested using ZSTDv01_isError()) 35 | */ 36 | size_t ZSTDv02_decompress( void* dst, size_t maxOriginalSize, 37 | const void* src, size_t compressedSize); 38 | 39 | /** 40 | ZSTDv02_findFrameSizeInfoLegacy() : get the source length and decompressed bound of a ZSTD frame compliant with v0.2.x format 41 | srcSize : The size of the 'src' buffer, at least as large as the frame pointed to by 'src' 42 | cSize (output parameter) : the number of bytes that would be read to decompress this frame 43 | or an error code if it fails (which can be tested using ZSTDv01_isError()) 44 | dBound (output parameter) : an upper-bound for the decompressed size of the data in the frame 45 | or ZSTD_CONTENTSIZE_ERROR if an error occurs 46 | 47 | note : assumes `cSize` and `dBound` are _not_ NULL. 48 | */ 49 | void ZSTDv02_findFrameSizeInfoLegacy(const void *src, size_t srcSize, 50 | size_t* cSize, unsigned long long* dBound); 51 | 52 | /** 53 | ZSTDv02_isError() : tells if the result of ZSTDv02_decompress() is an error 54 | */ 55 | unsigned ZSTDv02_isError(size_t code); 56 | 57 | 58 | /* ************************************* 59 | * Advanced functions 60 | ***************************************/ 61 | typedef struct ZSTDv02_Dctx_s ZSTDv02_Dctx; 62 | ZSTDv02_Dctx* ZSTDv02_createDCtx(void); 63 | size_t ZSTDv02_freeDCtx(ZSTDv02_Dctx* dctx); 64 | 65 | size_t ZSTDv02_decompressDCtx(void* ctx, 66 | void* dst, size_t maxOriginalSize, 67 | const void* src, size_t compressedSize); 68 | 69 | /* ************************************* 70 | * Streaming functions 71 | ***************************************/ 72 | size_t ZSTDv02_resetDCtx(ZSTDv02_Dctx* dctx); 73 | 74 | size_t ZSTDv02_nextSrcSizeToDecompress(ZSTDv02_Dctx* dctx); 75 | size_t ZSTDv02_decompressContinue(ZSTDv02_Dctx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize); 76 | /** 77 | Use above functions alternatively. 78 | ZSTD_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTD_decompressContinue(). 79 | ZSTD_decompressContinue() will use previous data blocks to improve compression if they are located prior to current block. 80 | Result is the number of bytes regenerated within 'dst'. 81 | It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some header. 82 | */ 83 | 84 | /* ************************************* 85 | * Prefix - version detection 86 | ***************************************/ 87 | #define ZSTDv02_magicNumber 0xFD2FB522 /* v0.2 */ 88 | 89 | 90 | #if defined (__cplusplus) 91 | } 92 | #endif 93 | 94 | #endif /* ZSTD_V02_H_4174539423 */ 95 | 96 | #endif /* USE_EXTERNAL_ZSTD */ 97 | -------------------------------------------------------------------------------- /zstd_v03.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_V03_H_298734209782 13 | #define ZSTD_V03_H_298734209782 14 | 15 | #if defined (__cplusplus) 16 | extern "C" { 17 | #endif 18 | 19 | /* ************************************* 20 | * Includes 21 | ***************************************/ 22 | #include /* size_t */ 23 | 24 | 25 | /* ************************************* 26 | * Simple one-step function 27 | ***************************************/ 28 | /** 29 | ZSTDv03_decompress() : decompress ZSTD frames compliant with v0.3.x format 30 | compressedSize : is the exact source size 31 | maxOriginalSize : is the size of the 'dst' buffer, which must be already allocated. 32 | It must be equal or larger than originalSize, otherwise decompression will fail. 33 | return : the number of bytes decompressed into destination buffer (originalSize) 34 | or an errorCode if it fails (which can be tested using ZSTDv01_isError()) 35 | */ 36 | size_t ZSTDv03_decompress( void* dst, size_t maxOriginalSize, 37 | const void* src, size_t compressedSize); 38 | 39 | /** 40 | ZSTDv03_findFrameSizeInfoLegacy() : get the source length and decompressed bound of a ZSTD frame compliant with v0.3.x format 41 | srcSize : The size of the 'src' buffer, at least as large as the frame pointed to by 'src' 42 | cSize (output parameter) : the number of bytes that would be read to decompress this frame 43 | or an error code if it fails (which can be tested using ZSTDv01_isError()) 44 | dBound (output parameter) : an upper-bound for the decompressed size of the data in the frame 45 | or ZSTD_CONTENTSIZE_ERROR if an error occurs 46 | 47 | note : assumes `cSize` and `dBound` are _not_ NULL. 48 | */ 49 | void ZSTDv03_findFrameSizeInfoLegacy(const void *src, size_t srcSize, 50 | size_t* cSize, unsigned long long* dBound); 51 | 52 | /** 53 | ZSTDv03_isError() : tells if the result of ZSTDv03_decompress() is an error 54 | */ 55 | unsigned ZSTDv03_isError(size_t code); 56 | 57 | 58 | /* ************************************* 59 | * Advanced functions 60 | ***************************************/ 61 | typedef struct ZSTDv03_Dctx_s ZSTDv03_Dctx; 62 | ZSTDv03_Dctx* ZSTDv03_createDCtx(void); 63 | size_t ZSTDv03_freeDCtx(ZSTDv03_Dctx* dctx); 64 | 65 | size_t ZSTDv03_decompressDCtx(void* ctx, 66 | void* dst, size_t maxOriginalSize, 67 | const void* src, size_t compressedSize); 68 | 69 | /* ************************************* 70 | * Streaming functions 71 | ***************************************/ 72 | size_t ZSTDv03_resetDCtx(ZSTDv03_Dctx* dctx); 73 | 74 | size_t ZSTDv03_nextSrcSizeToDecompress(ZSTDv03_Dctx* dctx); 75 | size_t ZSTDv03_decompressContinue(ZSTDv03_Dctx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize); 76 | /** 77 | Use above functions alternatively. 78 | ZSTD_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTD_decompressContinue(). 79 | ZSTD_decompressContinue() will use previous data blocks to improve compression if they are located prior to current block. 80 | Result is the number of bytes regenerated within 'dst'. 81 | It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some header. 82 | */ 83 | 84 | /* ************************************* 85 | * Prefix - version detection 86 | ***************************************/ 87 | #define ZSTDv03_magicNumber 0xFD2FB523 /* v0.3 */ 88 | 89 | 90 | #if defined (__cplusplus) 91 | } 92 | #endif 93 | 94 | #endif /* ZSTD_V03_H_298734209782 */ 95 | 96 | #endif /* USE_EXTERNAL_ZSTD */ 97 | -------------------------------------------------------------------------------- /zstd_v04.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTD_V04_H_91868324769238 13 | #define ZSTD_V04_H_91868324769238 14 | 15 | #if defined (__cplusplus) 16 | extern "C" { 17 | #endif 18 | 19 | /* ************************************* 20 | * Includes 21 | ***************************************/ 22 | #include /* size_t */ 23 | 24 | 25 | /* ************************************* 26 | * Simple one-step function 27 | ***************************************/ 28 | /** 29 | ZSTDv04_decompress() : decompress ZSTD frames compliant with v0.4.x format 30 | compressedSize : is the exact source size 31 | maxOriginalSize : is the size of the 'dst' buffer, which must be already allocated. 32 | It must be equal or larger than originalSize, otherwise decompression will fail. 33 | return : the number of bytes decompressed into destination buffer (originalSize) 34 | or an errorCode if it fails (which can be tested using ZSTDv01_isError()) 35 | */ 36 | size_t ZSTDv04_decompress( void* dst, size_t maxOriginalSize, 37 | const void* src, size_t compressedSize); 38 | 39 | /** 40 | ZSTDv04_findFrameSizeInfoLegacy() : get the source length and decompressed bound of a ZSTD frame compliant with v0.4.x format 41 | srcSize : The size of the 'src' buffer, at least as large as the frame pointed to by 'src' 42 | cSize (output parameter) : the number of bytes that would be read to decompress this frame 43 | or an error code if it fails (which can be tested using ZSTDv01_isError()) 44 | dBound (output parameter) : an upper-bound for the decompressed size of the data in the frame 45 | or ZSTD_CONTENTSIZE_ERROR if an error occurs 46 | 47 | note : assumes `cSize` and `dBound` are _not_ NULL. 48 | */ 49 | void ZSTDv04_findFrameSizeInfoLegacy(const void *src, size_t srcSize, 50 | size_t* cSize, unsigned long long* dBound); 51 | 52 | /** 53 | ZSTDv04_isError() : tells if the result of ZSTDv04_decompress() is an error 54 | */ 55 | unsigned ZSTDv04_isError(size_t code); 56 | 57 | 58 | /* ************************************* 59 | * Advanced functions 60 | ***************************************/ 61 | typedef struct ZSTDv04_Dctx_s ZSTDv04_Dctx; 62 | ZSTDv04_Dctx* ZSTDv04_createDCtx(void); 63 | size_t ZSTDv04_freeDCtx(ZSTDv04_Dctx* dctx); 64 | 65 | size_t ZSTDv04_decompressDCtx(ZSTDv04_Dctx* dctx, 66 | void* dst, size_t maxOriginalSize, 67 | const void* src, size_t compressedSize); 68 | 69 | 70 | /* ************************************* 71 | * Direct Streaming 72 | ***************************************/ 73 | size_t ZSTDv04_resetDCtx(ZSTDv04_Dctx* dctx); 74 | 75 | size_t ZSTDv04_nextSrcSizeToDecompress(ZSTDv04_Dctx* dctx); 76 | size_t ZSTDv04_decompressContinue(ZSTDv04_Dctx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize); 77 | /** 78 | Use above functions alternatively. 79 | ZSTD_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTD_decompressContinue(). 80 | ZSTD_decompressContinue() will use previous data blocks to improve compression if they are located prior to current block. 81 | Result is the number of bytes regenerated within 'dst'. 82 | It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some header. 83 | */ 84 | 85 | 86 | /* ************************************* 87 | * Buffered Streaming 88 | ***************************************/ 89 | typedef struct ZBUFFv04_DCtx_s ZBUFFv04_DCtx; 90 | ZBUFFv04_DCtx* ZBUFFv04_createDCtx(void); 91 | size_t ZBUFFv04_freeDCtx(ZBUFFv04_DCtx* dctx); 92 | 93 | size_t ZBUFFv04_decompressInit(ZBUFFv04_DCtx* dctx); 94 | size_t ZBUFFv04_decompressWithDictionary(ZBUFFv04_DCtx* dctx, const void* dict, size_t dictSize); 95 | 96 | size_t ZBUFFv04_decompressContinue(ZBUFFv04_DCtx* dctx, void* dst, size_t* maxDstSizePtr, const void* src, size_t* srcSizePtr); 97 | 98 | /** ************************************************ 99 | * Streaming decompression 100 | * 101 | * A ZBUFF_DCtx object is required to track streaming operation. 102 | * Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources. 103 | * Use ZBUFF_decompressInit() to start a new decompression operation. 104 | * ZBUFF_DCtx objects can be reused multiple times. 105 | * 106 | * Optionally, a reference to a static dictionary can be set, using ZBUFF_decompressWithDictionary() 107 | * It must be the same content as the one set during compression phase. 108 | * Dictionary content must remain accessible during the decompression process. 109 | * 110 | * Use ZBUFF_decompressContinue() repetitively to consume your input. 111 | * *srcSizePtr and *maxDstSizePtr can be any size. 112 | * The function will report how many bytes were read or written by modifying *srcSizePtr and *maxDstSizePtr. 113 | * Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again. 114 | * The content of dst will be overwritten (up to *maxDstSizePtr) at each function call, so save its content if it matters or change dst. 115 | * @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency) 116 | * or 0 when a frame is completely decoded 117 | * or an error code, which can be tested using ZBUFF_isError(). 118 | * 119 | * Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize / ZBUFF_recommendedDOutSize 120 | * output : ZBUFF_recommendedDOutSize==128 KB block size is the internal unit, it ensures it's always possible to write a full block when it's decoded. 121 | * input : ZBUFF_recommendedDInSize==128Kb+3; just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . 122 | * **************************************************/ 123 | unsigned ZBUFFv04_isError(size_t errorCode); 124 | const char* ZBUFFv04_getErrorName(size_t errorCode); 125 | 126 | 127 | /** The below functions provide recommended buffer sizes for Compression or Decompression operations. 128 | * These sizes are not compulsory, they just tend to offer better latency */ 129 | size_t ZBUFFv04_recommendedDInSize(void); 130 | size_t ZBUFFv04_recommendedDOutSize(void); 131 | 132 | 133 | /* ************************************* 134 | * Prefix - version detection 135 | ***************************************/ 136 | #define ZSTDv04_magicNumber 0xFD2FB524 /* v0.4 */ 137 | 138 | 139 | #if defined (__cplusplus) 140 | } 141 | #endif 142 | 143 | #endif /* ZSTD_V04_H_91868324769238 */ 144 | 145 | #endif /* USE_EXTERNAL_ZSTD */ 146 | -------------------------------------------------------------------------------- /zstd_v05.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTDv05_H 13 | #define ZSTDv05_H 14 | 15 | #if defined (__cplusplus) 16 | extern "C" { 17 | #endif 18 | 19 | /*-************************************* 20 | * Dependencies 21 | ***************************************/ 22 | #include /* size_t */ 23 | #include "mem.h" /* U64, U32 */ 24 | 25 | 26 | /* ************************************* 27 | * Simple functions 28 | ***************************************/ 29 | /*! ZSTDv05_decompress() : 30 | `compressedSize` : is the _exact_ size of the compressed blob, otherwise decompression will fail. 31 | `dstCapacity` must be large enough, equal or larger than originalSize. 32 | @return : the number of bytes decompressed into `dst` (<= `dstCapacity`), 33 | or an errorCode if it fails (which can be tested using ZSTDv05_isError()) */ 34 | size_t ZSTDv05_decompress( void* dst, size_t dstCapacity, 35 | const void* src, size_t compressedSize); 36 | 37 | /** 38 | ZSTDv05_findFrameSizeInfoLegacy() : get the source length and decompressed bound of a ZSTD frame compliant with v0.5.x format 39 | srcSize : The size of the 'src' buffer, at least as large as the frame pointed to by 'src' 40 | cSize (output parameter) : the number of bytes that would be read to decompress this frame 41 | or an error code if it fails (which can be tested using ZSTDv01_isError()) 42 | dBound (output parameter) : an upper-bound for the decompressed size of the data in the frame 43 | or ZSTD_CONTENTSIZE_ERROR if an error occurs 44 | 45 | note : assumes `cSize` and `dBound` are _not_ NULL. 46 | */ 47 | void ZSTDv05_findFrameSizeInfoLegacy(const void *src, size_t srcSize, 48 | size_t* cSize, unsigned long long* dBound); 49 | 50 | /* ************************************* 51 | * Helper functions 52 | ***************************************/ 53 | /* Error Management */ 54 | unsigned ZSTDv05_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ 55 | const char* ZSTDv05_getErrorName(size_t code); /*!< provides readable string for an error code */ 56 | 57 | 58 | /* ************************************* 59 | * Explicit memory management 60 | ***************************************/ 61 | /** Decompression context */ 62 | typedef struct ZSTDv05_DCtx_s ZSTDv05_DCtx; 63 | ZSTDv05_DCtx* ZSTDv05_createDCtx(void); 64 | size_t ZSTDv05_freeDCtx(ZSTDv05_DCtx* dctx); /*!< @return : errorCode */ 65 | 66 | /** ZSTDv05_decompressDCtx() : 67 | * Same as ZSTDv05_decompress(), but requires an already allocated ZSTDv05_DCtx (see ZSTDv05_createDCtx()) */ 68 | size_t ZSTDv05_decompressDCtx(ZSTDv05_DCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); 69 | 70 | 71 | /*-*********************** 72 | * Simple Dictionary API 73 | *************************/ 74 | /*! ZSTDv05_decompress_usingDict() : 75 | * Decompression using a pre-defined Dictionary content (see dictBuilder). 76 | * Dictionary must be identical to the one used during compression, otherwise regenerated data will be corrupted. 77 | * Note : dict can be NULL, in which case, it's equivalent to ZSTDv05_decompressDCtx() */ 78 | size_t ZSTDv05_decompress_usingDict(ZSTDv05_DCtx* dctx, 79 | void* dst, size_t dstCapacity, 80 | const void* src, size_t srcSize, 81 | const void* dict,size_t dictSize); 82 | 83 | /*-************************ 84 | * Advanced Streaming API 85 | ***************************/ 86 | typedef enum { ZSTDv05_fast, ZSTDv05_greedy, ZSTDv05_lazy, ZSTDv05_lazy2, ZSTDv05_btlazy2, ZSTDv05_opt, ZSTDv05_btopt } ZSTDv05_strategy; 87 | typedef struct { 88 | U64 srcSize; 89 | U32 windowLog; /* the only useful information to retrieve */ 90 | U32 contentLog; U32 hashLog; U32 searchLog; U32 searchLength; U32 targetLength; ZSTDv05_strategy strategy; 91 | } ZSTDv05_parameters; 92 | size_t ZSTDv05_getFrameParams(ZSTDv05_parameters* params, const void* src, size_t srcSize); 93 | 94 | size_t ZSTDv05_decompressBegin_usingDict(ZSTDv05_DCtx* dctx, const void* dict, size_t dictSize); 95 | void ZSTDv05_copyDCtx(ZSTDv05_DCtx* dstDCtx, const ZSTDv05_DCtx* srcDCtx); 96 | size_t ZSTDv05_nextSrcSizeToDecompress(ZSTDv05_DCtx* dctx); 97 | size_t ZSTDv05_decompressContinue(ZSTDv05_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); 98 | 99 | 100 | /*-*********************** 101 | * ZBUFF API 102 | *************************/ 103 | typedef struct ZBUFFv05_DCtx_s ZBUFFv05_DCtx; 104 | ZBUFFv05_DCtx* ZBUFFv05_createDCtx(void); 105 | size_t ZBUFFv05_freeDCtx(ZBUFFv05_DCtx* dctx); 106 | 107 | size_t ZBUFFv05_decompressInit(ZBUFFv05_DCtx* dctx); 108 | size_t ZBUFFv05_decompressInitDictionary(ZBUFFv05_DCtx* dctx, const void* dict, size_t dictSize); 109 | 110 | size_t ZBUFFv05_decompressContinue(ZBUFFv05_DCtx* dctx, 111 | void* dst, size_t* dstCapacityPtr, 112 | const void* src, size_t* srcSizePtr); 113 | 114 | /*-*************************************************************************** 115 | * Streaming decompression 116 | * 117 | * A ZBUFFv05_DCtx object is required to track streaming operations. 118 | * Use ZBUFFv05_createDCtx() and ZBUFFv05_freeDCtx() to create/release resources. 119 | * Use ZBUFFv05_decompressInit() to start a new decompression operation, 120 | * or ZBUFFv05_decompressInitDictionary() if decompression requires a dictionary. 121 | * Note that ZBUFFv05_DCtx objects can be reused multiple times. 122 | * 123 | * Use ZBUFFv05_decompressContinue() repetitively to consume your input. 124 | * *srcSizePtr and *dstCapacityPtr can be any size. 125 | * The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr. 126 | * Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again. 127 | * The content of @dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters or change @dst. 128 | * @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to help latency) 129 | * or 0 when a frame is completely decoded 130 | * or an error code, which can be tested using ZBUFFv05_isError(). 131 | * 132 | * Hint : recommended buffer sizes (not compulsory) : ZBUFFv05_recommendedDInSize() / ZBUFFv05_recommendedDOutSize() 133 | * output : ZBUFFv05_recommendedDOutSize==128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded. 134 | * input : ZBUFFv05_recommendedDInSize==128Kb+3; just follow indications from ZBUFFv05_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . 135 | * *******************************************************************************/ 136 | 137 | 138 | /* ************************************* 139 | * Tool functions 140 | ***************************************/ 141 | unsigned ZBUFFv05_isError(size_t errorCode); 142 | const char* ZBUFFv05_getErrorName(size_t errorCode); 143 | 144 | /** Functions below provide recommended buffer sizes for Compression or Decompression operations. 145 | * These sizes are just hints, and tend to offer better latency */ 146 | size_t ZBUFFv05_recommendedDInSize(void); 147 | size_t ZBUFFv05_recommendedDOutSize(void); 148 | 149 | 150 | 151 | /*-************************************* 152 | * Constants 153 | ***************************************/ 154 | #define ZSTDv05_MAGICNUMBER 0xFD2FB525 /* v0.5 */ 155 | 156 | 157 | 158 | 159 | #if defined (__cplusplus) 160 | } 161 | #endif 162 | 163 | #endif /* ZSTDv0505_H */ 164 | 165 | #endif /* USE_EXTERNAL_ZSTD */ 166 | -------------------------------------------------------------------------------- /zstdmt_compress.h: -------------------------------------------------------------------------------- 1 | #ifndef USE_EXTERNAL_ZSTD 2 | /* 3 | * Copyright (c) Meta Platforms, Inc. and affiliates. 4 | * All rights reserved. 5 | * 6 | * This source code is licensed under both the BSD-style license (found in the 7 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 8 | * in the COPYING file in the root directory of this source tree). 9 | * You may select, at your option, one of the above-listed licenses. 10 | */ 11 | 12 | #ifndef ZSTDMT_COMPRESS_H 13 | #define ZSTDMT_COMPRESS_H 14 | 15 | /* === Dependencies === */ 16 | #include "zstd_deps.h" /* size_t */ 17 | #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters */ 18 | #include "zstd.h" /* ZSTD_inBuffer, ZSTD_outBuffer, ZSTDLIB_API */ 19 | 20 | /* Note : This is an internal API. 21 | * These APIs used to be exposed with ZSTDLIB_API, 22 | * because it used to be the only way to invoke MT compression. 23 | * Now, you must use ZSTD_compress2 and ZSTD_compressStream2() instead. 24 | * 25 | * This API requires ZSTD_MULTITHREAD to be defined during compilation, 26 | * otherwise ZSTDMT_createCCtx*() will fail. 27 | */ 28 | 29 | /* === Constants === */ 30 | #ifndef ZSTDMT_NBWORKERS_MAX /* a different value can be selected at compile time */ 31 | # define ZSTDMT_NBWORKERS_MAX ((sizeof(void*)==4) /*32-bit*/ ? 64 : 256) 32 | #endif 33 | #ifndef ZSTDMT_JOBSIZE_MIN /* a different value can be selected at compile time */ 34 | # define ZSTDMT_JOBSIZE_MIN (512 KB) 35 | #endif 36 | #define ZSTDMT_JOBLOG_MAX (MEM_32bits() ? 29 : 30) 37 | #define ZSTDMT_JOBSIZE_MAX (MEM_32bits() ? (512 MB) : (1024 MB)) 38 | 39 | 40 | /* ======================================================== 41 | * === Private interface, for use by ZSTD_compress.c === 42 | * === Not exposed in libzstd. Never invoke directly === 43 | * ======================================================== */ 44 | 45 | /* === Memory management === */ 46 | typedef struct ZSTDMT_CCtx_s ZSTDMT_CCtx; 47 | /* Requires ZSTD_MULTITHREAD to be defined during compilation, otherwise it will return NULL. */ 48 | ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, 49 | ZSTD_customMem cMem, 50 | ZSTD_threadPool *pool); 51 | size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx); 52 | 53 | size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx); 54 | 55 | /* === Streaming functions === */ 56 | 57 | size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx); 58 | 59 | /*! ZSTDMT_initCStream_internal() : 60 | * Private use only. Init streaming operation. 61 | * expects params to be valid. 62 | * must receive dict, or cdict, or none, but not both. 63 | * mtctx can be freshly constructed or reused from a prior compression. 64 | * If mtctx is reused, memory allocations from the prior compression may not be freed, 65 | * even if they are not needed for the current compression. 66 | * @return : 0, or an error code */ 67 | size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* mtctx, 68 | const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, 69 | const ZSTD_CDict* cdict, 70 | ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); 71 | 72 | /*! ZSTDMT_compressStream_generic() : 73 | * Combines ZSTDMT_compressStream() with optional ZSTDMT_flushStream() or ZSTDMT_endStream() 74 | * depending on flush directive. 75 | * @return : minimum amount of data still to be flushed 76 | * 0 if fully flushed 77 | * or an error code 78 | * note : needs to be init using any ZSTD_initCStream*() variant */ 79 | size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, 80 | ZSTD_outBuffer* output, 81 | ZSTD_inBuffer* input, 82 | ZSTD_EndDirective endOp); 83 | 84 | /*! ZSTDMT_toFlushNow() 85 | * Tell how many bytes are ready to be flushed immediately. 86 | * Probe the oldest active job (not yet entirely flushed) and check its output buffer. 87 | * If return 0, it means there is no active job, 88 | * or, it means oldest job is still active, but everything produced has been flushed so far, 89 | * therefore flushing is limited by speed of oldest job. */ 90 | size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx); 91 | 92 | /*! ZSTDMT_updateCParams_whileCompressing() : 93 | * Updates only a selected set of compression parameters, to remain compatible with current frame. 94 | * New parameters will be applied to next compression job. */ 95 | void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_params* cctxParams); 96 | 97 | /*! ZSTDMT_getFrameProgression(): 98 | * tells how much data has been consumed (input) and produced (output) for current frame. 99 | * able to count progression inside worker threads. 100 | */ 101 | ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx); 102 | 103 | #endif /* ZSTDMT_COMPRESS_H */ 104 | 105 | #endif /* USE_EXTERNAL_ZSTD */ 106 | --------------------------------------------------------------------------------