Codebase list c-blosc / f6a4166
New upstream version 1.20.1+ds1 Håvard Flaget Aasen 3 years ago
45 changed file(s) with 1573 addition(s) and 1041 deletion(s). Raw diff Collapse all Expand all
0 name: CI CMake
1 on: [push, pull_request]
2 jobs:
3 ci-cmake:
4 name: ${{ matrix.name }}
5 runs-on: ${{ matrix.os }}
6 strategy:
7 fail-fast: false
8 matrix:
9 name: [
10 Ubuntu GCC,
11 Ubuntu GCC OSB,
12 Ubuntu GCC External LZ4,
13 Ubuntu GCC External SNAPPY,
14 Ubuntu GCC External ZLIB,
15 Ubuntu GCC External ZSTD,
16 Ubuntu Clang,
17 Ubuntu Clang No SSE2,
18 Ubuntu Clang No AVX2,
19 Ubuntu Clang No AVX2 No SSE2,
20 Ubuntu Clang No LZ4,
21 Ubuntu Clang No ZLIB,
22 Ubuntu Clang No ZSTD,
23 Windows MSVC Win32,
24 Windows MSVC Win64,
25 Windows GCC,
26 macOS Clang,
27 macOS GCC
28 ]
29 include:
30 - name: Ubuntu GCC
31 os: ubuntu-latest
32 compiler: gcc
33
34 # Out of source build
35 - name: Ubuntu GCC OSB
36 os: ubuntu-latest
37 compiler: gcc
38 build-dir: ../build
39 build-src-dir: ../c-blosc
40
41 - name: Ubuntu GCC External LZ4
42 os: ubuntu-latest
43 compiler: gcc
44 packages: liblz4-1 liblz4-dev
45 cmake-args: -DPREFER_EXTERNAL_LZ4=ON
46
47 - name: Ubuntu GCC External SNAPPY
48 os: ubuntu-latest
49 compiler: gcc
50 packages: libsnappy-dev
51 cmake-args: -DDEACTIVATE_SNAPPY=OFF
52
53 - name: Ubuntu GCC External ZLIB
54 os: ubuntu-latest
55 compiler: gcc
56 packages: zlib1g-dev
57 cmake-args: -DPREFER_EXTERNAL_ZLIB=ON
58
59 - name: Ubuntu GCC External ZSTD
60 os: ubuntu-latest
61 compiler: gcc
62 packages: zstd libzstd-dev
63 cmake-args: -DPREFER_EXTERNAL_ZSTD=ON
64
65 - name: Ubuntu Clang
66 os: ubuntu-latest
67 compiler: clang
68
69 - name: Ubuntu Clang No SSE2
70 os: ubuntu-latest
71 compiler: clang
72 cmake-args: -DDEACTIVATE_SSE2=ON
73
74 - name: Ubuntu Clang No AVX2
75 os: ubuntu-latest
76 compiler: clang
77 cmake-args: -DDEACTIVATE_AVX2=ON
78
79 - name: Ubuntu Clang No AVX2 No SSE2
80 os: ubuntu-latest
81 compiler: clang
82 cmake-args: -DDEACTIVATE_AVX2=ON -DDEACTIVATE_SSE2=ON
83
84 - name: Ubuntu Clang No LZ4
85 os: ubuntu-latest
86 compiler: clang
87 cmake-args: -DDEACTIVATE_LZ4=ON
88
89 - name: Ubuntu Clang No ZLIB
90 os: ubuntu-latest
91 compiler: clang
92 cmake-args: -DDEACTIVATE_ZLIB=ON
93
94 - name: Ubuntu Clang No ZSTD
95 os: ubuntu-latest
96 compiler: clang
97 cmake-args: -DDEACTIVATE_ZSTD=ON
98
99 - name: Windows MSVC Win32
100 os: windows-latest
101 compiler: cl
102 cmake-args: -A Win32
103
104 - name: Windows MSVC Win64
105 os: windows-latest
106 compiler: cl
107 cmake-args: -A x64
108
109 - name: Windows GCC
110 os: windows-latest
111 compiler: gcc
112 cmake-args: -G Ninja
113
114 - name: macOS Clang
115 os: macOS-latest
116 compiler: clang
117
118 - name: macOS GCC
119 os: macOS-latest
120 compiler: gcc
121
122 steps:
123 - uses: actions/checkout@v1
124
125 - name: Install packages (Ubuntu)
126 if: runner.os == 'Linux' && matrix.packages
127 run: |
128 sudo apt-get update
129 sudo apt-get install -y ${{ matrix.packages }}
130
131 - name: Install packages (Windows)
132 if: runner.os == 'Windows'
133 run: |
134 choco install ninja ${{ matrix.packages }}
135
136 - name: Install packages (macOS)
137 if: runner.os == 'macOS'
138 run: |
139 brew install ninja ${{ matrix.packages }}
140
141 - name: Generate project files
142 run: |
143 mkdir ${{ matrix.build-dir || '.not-used' }}
144 cd ${{ matrix.build-dir || '.' }}
145 cmake ${{ matrix.build-src-dir || '.' }} ${{ matrix.cmake-args }} -DCMAKE_BUILD_TYPE=${{ matrix.build-config || 'Release' }} -DBUILD_SHARED_LIBS=OFF -DBUILD_FUZZERS=ON
146 env:
147 CC: ${{ matrix.compiler }}
148 CFLAGS: ${{ matrix.cflags }}
149 LDFLAGS: ${{ matrix.ldflags }}
150 CI: true
151
152 - name: Compile source code
153 run: |
154 cd ${{ matrix.build-dir || '.' }}
155 cmake --build . --config ${{ matrix.build-config || 'Release' }}
156
157 - name: Run test cases
158 run: |
159 cd ${{ matrix.build-dir || '.' }}
160 ctest -C Release --output-on-failure --max-width 120
0 name: CIFuzz
1 on: [pull_request]
2 jobs:
3 Fuzzing:
4 runs-on: ubuntu-latest
5 steps:
6 - name: Build Fuzzers
7 uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
8 with:
9 oss-fuzz-project-name: 'c-blosc'
10 dry-run: false
11 - name: Run Fuzzers
12 uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
13 with:
14 oss-fuzz-project-name: 'c-blosc'
15 fuzz-seconds: 600
16 dry-run: false
17 - name: Upload Crash
18 uses: actions/upload-artifact@v1
19 if: failure()
20 with:
21 name: artifacts
22 path: ./out/artifacts
+0
-80
.travis.yml less more
0 env:
1 global:
2 - CONAN_USERNAME: "francescalted"
3 - CONAN_LOGIN_USERNAME: "francescalted"
4 - CONAN_CHANNEL: "stable"
5 - CONAN_UPLOAD: "https://api.bintray.com/conan/blosc/Conan"
6 - CONAN_TOTAL_PAGES: 2
7
8 linux: &linux
9 os: linux
10 sudo: required
11 language: python
12 python: "3.6"
13 services:
14 - docker
15
16 osx: &osx
17 os: osx
18 language: generic
19
20 matrix:
21 include:
22 - <<: *osx
23 osx_image: xcode8.3
24 env: CONAN_APPLE_CLANG_VERSIONS=8.1 CONAN_CURRENT_PAGE=1 CONAN_RUN_TESTS=1
25 - <<: *osx
26 osx_image: xcode8.3
27 env: CONAN_APPLE_CLANG_VERSIONS=8.1 CONAN_CURRENT_PAGE=2
28
29 - <<: *osx
30 osx_image: xcode9
31 env: CONAN_APPLE_CLANG_VERSIONS=9.0 CONAN_CURRENT_PAGE=1 CONAN_RUN_TESTS=1
32 - <<: *osx
33 osx_image: xcode9
34 env: CONAN_APPLE_CLANG_VERSIONS=9.0 CONAN_CURRENT_PAGE=2
35
36 - <<: *linux
37 env: CONAN_GCC_VERSIONS=4.9 CONAN_DOCKER_IMAGE=lasote/conangcc49 CONAN_CURRENT_PAGE=1 CONAN_RUN_TESTS=1
38 - <<: *linux
39 env: CONAN_GCC_VERSIONS=4.9 CONAN_DOCKER_IMAGE=lasote/conangcc49 CONAN_CURRENT_PAGE=2
40
41 - <<: *linux
42 env: CONAN_GCC_VERSIONS=5 CONAN_DOCKER_IMAGE=lasote/conangcc5 CONAN_CURRENT_PAGE=1 CONAN_RUN_TESTS=1
43 - <<: *linux
44 env: CONAN_GCC_VERSIONS=5 CONAN_DOCKER_IMAGE=lasote/conangcc5 CONAN_CURRENT_PAGE=2
45
46 - <<: *linux
47 env: CONAN_GCC_VERSIONS=6 CONAN_DOCKER_IMAGE=lasote/conangcc6 CONAN_CURRENT_PAGE=1 CONAN_RUN_TESTS=1
48 - <<: *linux
49 env: CONAN_GCC_VERSIONS=6 CONAN_DOCKER_IMAGE=lasote/conangcc6 CONAN_CURRENT_PAGE=2
50
51 - <<: *linux
52 env: CONAN_GCC_VERSIONS=7 CONAN_DOCKER_IMAGE=lasote/conangcc7 CONAN_CURRENT_PAGE=1 CONAN_RUN_TESTS=1
53 - <<: *linux
54 env: CONAN_GCC_VERSIONS=7 CONAN_DOCKER_IMAGE=lasote/conangcc7 CONAN_CURRENT_PAGE=2
55
56 - <<: *linux
57 env: CONAN_CLANG_VERSIONS=3.9 CONAN_DOCKER_IMAGE=lasote/conanclang39 CONAN_CURRENT_PAGE=1 CONAN_RUN_TESTS=1
58 - <<: *linux
59 env: CONAN_CLANG_VERSIONS=3.9 CONAN_DOCKER_IMAGE=lasote/conanclang39 CONAN_CURRENT_PAGE=2
60
61 - <<: *linux
62 env: CONAN_CLANG_VERSIONS=4.0 CONAN_DOCKER_IMAGE=lasote/conanclang40 CONAN_CURRENT_PAGE=1 CONAN_RUN_TESTS=1
63 - <<: *linux
64 env: CONAN_CLANG_VERSIONS=4.0 CONAN_DOCKER_IMAGE=lasote/conanclang40 CONAN_CURRENT_PAGE=2
65
66 before_script:
67 - if [ "$TRAVIS_OS_NAME" == "osx" ]; then
68 brew update;
69 brew upgrade pyenv;
70 pyenv install 3.6.6;
71 eval "$(pyenv init -)";
72 pyenv global 3.6.6;
73 python3 --version;
74 pip3 install --upgrade pip;
75 fi
76 - pip3 install conan_package_tools==0.19.3
77
78 script:
79 - python3 build.py
00 ===============================================================
1 Announcing C-Blosc 1.17.1
1 Announcing C-Blosc 1.20.1
22 A blocking, shuffling and lossless compression library for C
33 ===============================================================
44
55 What is new?
66 ============
77
8 A maintenance release where LZ4 and Zstd internal codecs have been updated
9 to latest versions.
8 This is a maintenance release. Vendored zlib 1.2.8 is now compatible
9 with Python 3.8 in recent Mac OSX. For details, see:
10 https://github.com/Blosc/python-blosc/issues/229
1011
1112 For more info, please see the release notes in:
1213
88 # build the shared library version of the Blosc library
99 # BUILD_TESTS: default ON
1010 # build test programs and generates the "test" target
11 # BUILD_FUZZERS: default ON
12 # build fuzz test programs and generates the "test" target
1113 # BUILD_BENCHMARKS: default ON
1214 # build the benchmark program
1315 # DEACTIVATE_SSE2: default OFF
1618 # do not attempt to build with AVX2 instructions
1719 # DEACTIVATE_LZ4: default OFF
1820 # do not include support for the LZ4 library
19 # DEACTIVATE_SNAPPY: default OFF
21 # DEACTIVATE_SNAPPY: default ON
2022 # do not include support for the Snappy library
2123 # DEACTIVATE_ZLIB: default OFF
2224 # do not include support for the Zlib library
2628 # do not check for symbols in shared or static libraries
2729 # PREFER_EXTERNAL_LZ4: default OFF
2830 # when found, use the installed LZ4 libs instead of included
29 # sources
30 # PREFER_EXTERNAL_SNAPPY: default OFF
31 # when found, use the installed Snappy libs instead of included
3231 # sources
3332 # PREFER_EXTERNAL_ZLIB: default OFF
3433 # when found, use the installed zlib libs instead of included
7473 if (NOT CMAKE_VERSION VERSION_LESS 3.3)
7574 cmake_policy(SET CMP0063 NEW)
7675 endif()
77 project(blosc)
76 project(blosc C)
7877
7978 # parse the full version numbers from blosc.h
8079 file(READ ${CMAKE_CURRENT_SOURCE_DIR}/blosc/blosc.h _blosc_h_contents)
9594 option(BUILD_SHARED
9695 "Build a shared library version of the blosc library." ON)
9796 option(BUILD_TESTS
98 "Build test programs form the blosc compression library" ON)
97 "Build test programs from the blosc compression library" ON)
98 option(BUILD_FUZZERS
99 "Build fuzzer programs from the blosc compression library" ${BUILD_STATIC})
99100 option(BUILD_BENCHMARKS
100 "Build benchmark programs form the blosc compression library" ON)
101 "Build benchmark programs from the blosc compression library" ON)
101102 option(DEACTIVATE_SSE2
102 "Do not attempt to build with SSE2 instructions" OFF)
103 "Do not attempt to build with SSE2 instructions" OFF)
103104 option(DEACTIVATE_AVX2
104 "Do not attempt to build with AVX2 instructions" OFF)
105 "Do not attempt to build with AVX2 instructions" OFF)
105106 option(DEACTIVATE_LZ4
106107 "Do not include support for the LZ4 library." OFF)
107108 option(DEACTIVATE_SNAPPY
108 "Do not include support for the Snappy library." OFF)
109 "Do not include support for the Snappy library." ON)
109110 option(DEACTIVATE_ZLIB
110111 "Do not include support for the Zlib library." OFF)
111112 option(DEACTIVATE_ZSTD
112 "Do not include support for the Zstd library." OFF)
113 "Do not include support for the Zstd library." OFF)
113114 option(DEACTIVATE_SYMBOLS_CHECK
114 "Do not check for symbols in shared or static libraries." ON)
115 "Do not check for symbols in shared or static libraries." ON)
115116 option(PREFER_EXTERNAL_LZ4
116117 "Find and use external LZ4 library instead of included sources." OFF)
117 option(PREFER_EXTERNAL_SNAPPY
118 "Find and use external Snappy library instead of included sources." OFF)
119118 option(PREFER_EXTERNAL_ZLIB
120119 "Find and use external Zlib library instead of included sources." OFF)
121120 option(PREFER_EXTERNAL_ZSTD
136135 endif(NOT DEACTIVATE_LZ4)
137136
138137 if(NOT DEACTIVATE_SNAPPY)
139 if(PREFER_EXTERNAL_SNAPPY)
140 find_package(Snappy)
141 else()
142 message(STATUS "Using Snappy internal sources.")
143 endif(PREFER_EXTERNAL_SNAPPY)
144 # HAVE_SNAPPY will be set to true because even if the library is not found,
145 # we will use the included sources for it
146 set(HAVE_SNAPPY TRUE)
138 find_package(Snappy)
139 if(SNAPPY_FOUND)
140 message(STATUS "Activating support for SNAPPY.")
141 set(HAVE_SNAPPY TRUE)
142 else()
143 message(STATUS "SNAPPY *not* found. De-activating support for it.")
144 endif()
147145 endif(NOT DEACTIVATE_SNAPPY)
148146
149147 if(NOT DEACTIVATE_ZLIB)
254252 set(COMPILER_SUPPORT_SSE2 FALSE)
255253 endif()
256254
257 # disable AVX2 if specified
258 if(DEACTIVATE_AVX2)
255 # disable AVX2 if specified or if SSE is deactivated
256 if(DEACTIVATE_AVX2 OR DEACTIVATE_SSE2)
259257 set(COMPILER_SUPPORT_AVX2 FALSE)
260258 endif()
261259
322320 add_subdirectory(tests)
323321 add_subdirectory(compat)
324322 endif(BUILD_TESTS)
323
324 if(BUILD_FUZZERS)
325 if(NOT BUILD_STATIC)
326 message(FATAL_ERROR "BUILD_FUZZERS requires BUILD_STATIC to be enabled.")
327 endif()
328 enable_testing()
329 add_subdirectory(tests/fuzz)
330 endif(BUILD_FUZZERS)
325331
326332 if(BUILD_BENCHMARKS)
327333 add_subdirectory(bench)
+0
-5
CODE_OF_CONDUCT.md less more
0 # Code of Conduct
1
2 The Blosc community has adopted a Code of Conduct that we expect project participants to adhere to.
3 Please read the [full text](https://github.com/Blosc/CodeOfConduct/README.md)
4 so that you can understand what actions will and will not be tolerated.
22 |--------|---------|-----|
33 | Blosc Development Team | blosc@blosc.org | http://www.blosc.org |
44
5 | Gitter | Travis CI | Appveyor | NumFOCUS |
6 |--------|-----------|----------|----------|
7 | [![Build Status](https://badges.gitter.im/Blosc/c-blosc.svg)](https://gitter.im/Blosc/c-blosc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | [![Build Status](https://travis-ci.org/Blosc/c-blosc.svg?branch=master)](https://travis-ci.org/Blosc/c-blosc) | [![Build Status](https://ci.appveyor.com/api/projects/status/3mlyjc1ak0lbkmte?svg=true)](https://ci.appveyor.com/project/FrancescAlted/c-blosc/branch/master) | [![Powered by NumFOCUS](https://img.shields.io/badge/powered%20by-NumFOCUS-orange.svg?style=flat&colorA=E1523D&colorB=007D8A)](http://numfocus.org) |
8
5 | Gitter | GH Actions | NumFOCUS | Code of Conduct |
6 |--------|------------|----------|-----------------|
7 | [![Gitter](https://badges.gitter.im/Blosc/c-blosc.svg)](https://gitter.im/Blosc/c-blosc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | [![CI CMake](https://github.com/Blosc/c-blosc/workflows/CI%20CMake/badge.svg)](https://github.com/Blosc/c-blosc/actions?query=workflow%3A%22CI+CMake%22) | [![Powered by NumFOCUS](https://img.shields.io/badge/powered%20by-NumFOCUS-orange.svg?style=flat&colorA=E1523D&colorB=007D8A)](http://numfocus.org) | [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](code_of_conduct.md) |
98
109 ## What is it?
1110
0 Blosc Chunk Format
1 ==================
2
3 The chunk is composed by a header and a blocks / splits section::
4
5 +---------+--------+---------+
6 | header | blocks / splits |
7 +---------+--------+---------+
8
9 These are described below.
10
11 The header section
12 ------------------
13
14 Blosc (as of Version 1.0.0) has the following 16 byte header that stores
15 information about the compressed buffer::
16
17 |-0-|-1-|-2-|-3-|-4-|-5-|-6-|-7-|-8-|-9-|-A-|-B-|-C-|-D-|-E-|-F-|
18 ^ ^ ^ ^ | nbytes | blocksize | cbytes |
19 | | | |
20 | | | +--typesize
21 | | +------flags
22 | +----------versionlz
23 +--------------version
24
25 Datatypes of the header entries
26 -------------------------------
27
28 All entries are little endian.
29
30 :version:
31 (``uint8``) Blosc format version.
32 :versionlz:
33 (``uint8``) Version of the internal compressor used.
34 :flags and compressor enumeration:
35 (``bitfield``) The flags of the buffer
36
37 :bit 0 (``0x01``):
38 Whether the byte-shuffle filter has been applied or not.
39 :bit 1 (``0x02``):
40 Whether the internal buffer is a pure memcpy or not.
41 :bit 2 (``0x04``):
42 Whether the bit-shuffle filter has been applied or not.
43 :bit 3 (``0x08``):
44 Reserved, must be zero.
45 :bit 4 (``0x10``):
46 If set, the blocks will not be split in sub-blocks during compression.
47 :bit 5 (``0x20``):
48 Part of the enumeration for compressors.
49 :bit 6 (``0x40``):
50 Part of the enumeration for compressors.
51 :bit 7 (``0x80``):
52 Part of the enumeration for compressors.
53
54 The last three bits form an enumeration that allows to use alternative
55 compressors.
56
57 :``0``:
58 ``blosclz``
59 :``1``:
60 ``lz4`` or ``lz4hc``
61 :``2``:
62 ``snappy``
63 :``3``:
64 ``zlib``
65 :``4``:
66 ``zstd``
67
68 :typesize:
69 (``uint8``) Number of bytes for the atomic type.
70 :nbytes:
71 (``uint32``) Uncompressed size of the buffer (this header is not included).
72 :blocksize:
73 (``uint32``) Size of internal blocks.
74 :cbytes:
75 (``uint32``) Compressed size of the buffer (including this header).
76
77 The blocks / splits section
78 ---------------------------
79
80 After the header, there come the blocks / splits section. Blocks are equal-sized parts of the chunk, except for the last block that can be shorter or equal than the rest.
81
82 At the beginning of the blocks section, there come a list of `int32_t bstarts` to indicate where the different encoded blocks starts (counting from the end of this `bstarts` section)::
83
84 +=========+=========+========+=========+
85 | bstart0 | bstart1 | ... | bstartN |
86 +=========+=========+========+=========+
87
88 Finally, it comes the actual list of compressed blocks / splits data streams. It turns out that a block may optionally (see bit 4 in `flags` above) be further split in so-called splits which are the actual data streams that are transmitted to codecs for compression. If a block is not split, then the split is equivalent to a whole block. Before each split in the list, there is the compressed size of it, expressed as an `int32_t`::
89
90 +========+========+========+========+========+========+========+
91 | csize0 | split0 | csize1 | split1 | ... | csizeN | splitN |
92 +========+========+========+========+========+========+========+
93
94
95 *Note*: all the integers are stored in little endian.
96
+0
-65
README_HEADER.rst less more
0 Blosc Header Format
1 ===================
2
3 Blosc (as of Version 1.0.0) has the following 16 byte header that stores
4 information about the compressed buffer::
5
6 |-0-|-1-|-2-|-3-|-4-|-5-|-6-|-7-|-8-|-9-|-A-|-B-|-C-|-D-|-E-|-F-|
7 ^ ^ ^ ^ | nbytes | blocksize | ctbytes |
8 | | | |
9 | | | +--typesize
10 | | +------flags
11 | +----------versionlz
12 +--------------version
13
14 Datatypes of the Header Entries
15 -------------------------------
16
17 All entries are little endian.
18
19 :version:
20 (``uint8``) Blosc format version.
21 :versionlz:
22 (``uint8``) Version of the internal compressor used.
23 :flags and compressor enumeration:
24 (``bitfield``) The flags of the buffer
25
26 :bit 0 (``0x01``):
27 Whether the byte-shuffle filter has been applied or not.
28 :bit 1 (``0x02``):
29 Whether the internal buffer is a pure memcpy or not.
30 :bit 2 (``0x04``):
31 Whether the bit-shuffle filter has been applied or not.
32 :bit 3 (``0x08``):
33 Reserved, must be zero.
34 :bit 4 (``0x10``):
35 If set, the blocks will not be split in sub-blocks during compression.
36 :bit 5 (``0x20``):
37 Part of the enumeration for compressors.
38 :bit 6 (``0x40``):
39 Part of the enumeration for compressors.
40 :bit 7 (``0x80``):
41 Part of the enumeration for compressors.
42
43 The last three bits form an enumeration that allows to use alternative
44 compressors.
45
46 :``0``:
47 ``blosclz``
48 :``1``:
49 ``lz4`` or ``lz4hc``
50 :``2``:
51 ``snappy``
52 :``3``:
53 ``zlib``
54 :``4``:
55 ``zstd``
56
57 :typesize:
58 (``uint8``) Number of bytes for the atomic type.
59 :nbytes:
60 (``uint32``) Uncompressed size of the buffer.
61 :blocksize:
62 (``uint32``) Size of internal blocks.
63 :ctbytes:
64 (``uint32``) Compressed size of the buffer.
00 ===========================
11 Release notes for C-Blosc
22 ===========================
3
4 Changes from 1.20.0 to 1.20.1
5 =============================
6
7 * Added `<unistd.h>` in vendored zlib 1.2.8 for compatibility with Python 3.8
8 in recent Mac OSX. For details, see:
9 https://github.com/Blosc/python-blosc/issues/229
10
11 Changes from 1.19.1 to 1.20.0
12 =============================
13
14 * More saftey checks have been implemented so that potential flaws
15 discovered by new fuzzers in OSS-Fuzzer are fixed now. Thanks to
16 Nathan Moinvaziri (@nmoinvaz).
17
18 * BloscLZ updated to 2.3.0. Expect better compression ratios for faster
19 codecs. For details, see our new blog post:
20 https://blosc.org/posts/beast-release/
21
22 * Fixed the `_xgetbv()` collision. Thanks to Michał Górny (@mgorny).
23
24 * The chunk format has been fully described so that 3rd party software
25 may come with a different implementation, but still compatible with
26 C-Blosc chunks.
27
28
29 Changes from 1.19.0 to 1.19.1
30 =============================
31
32 - pthread_create() errors are now handled and propagated back to the user.
33 See https://github.com/Blosc/c-blosc/pull/299.
34
35
36 Changes from 1.18.1 to 1.19.0
37 =============================
38
39 - The length of automatic blocksizes for fast codecs (lz4, blosclz) has
40 been incremented quite a bit (up to 256 KB) for better compression ratios.
41 The performance in modern CPUs (with at least 256 KB in L2 cache) should
42 be better too (for older CPUs the performance should stay roughly the same).
43
44 - Continuous integration has been migrated to GitHub actions and much
45 more scenarios are tested (specially linking with external codecs).
46 Also, a new OSS-Fuzz workflow has been added for increased detection
47 of possible vulnerabilities. Thanks to Nathan Moinvaziri.
48
49 - For small buffers that cannot be compressed (typically < 128 bytes),
50 `blosc_compress()` returns now a 0 (cannot compress) instead of a negative
51 number (internal error). See https://github.com/Blosc/c-blosc/pull/294.
52 Thanks to @kalvdans for providing the initial patch.
53
54 - blosclz codec updated to 2.1.0. Expect better compression ratios and
55 performance in a wider variety of scenarios.
56
57 - `blosc_decompress_unsafe()`, `blosc_decompress_ctx_unsafe()` and
58 `blosc_getitem_unsafe()` have been removed because they are dangerous
59 and after latest improvements, they should not be used in production.
60
61 - zstd codec updated to 1.4.5.
62
63 - Conan packaging has been deprecated (from now on, we should try
64 to focus on supporting wheels only).
65
66
67 Changes from 1.17.1 to 1.18.1
68 =============================
69
70 - Fixed the copy of the leftovers of a chunk when its size is not a
71 multiple of the typesize. Although this is a very unusual situation,
72 it can certainly happen (e.g.
73 https://github.com/Blosc/python-blosc/issues/220).
374
475
576 Changes from 1.17.0 to 1.17.1
4444 $ cd ../compat
4545 $ export LD_LIBRARY_PATH=../build/blosc
4646 $ gcc -o filegen filegen.c -L$LD_LIBRARY_PATH -lblosc -I../blosc
47 $ ./filegen compress lz4 blosc-lz4-1.y.z.cdata
47 $ ./filegen compress lz4 blosc-1.y.z-lz4.cdata
4848
4949 In order to make sure that we are not breaking forward compatibility,
5050 link and run the `compat/filegen` utility against different versions of
5757
5858 Then, test the file created with the new version with::
5959
60 $ ./filegen decompress blosc-lz4-1.y.z.cdata
60 $ ./filegen decompress blosc-1.y.z-lz4.cdata
61
62 If that works and you want to keep track of this for future compatibility checks
63 just add the new file to the suite::
64
65 $ git add blosc-1.y.z-lz4.cdata
66 $ git commit -m"Add a new cdata file for compatibility checks"
6167
6268 Repeat this for every codec shipped with Blosc (blosclz, lz4, lz4hc, snappy,
6369 zlib and zstd).
6571 Tagging
6672 -------
6773
68 - Create a tag ``X.Y.Z`` from ``master``. Use the next message::
74 - Create a tag ``X.Y.Z`` from ``master``::
6975
76 $ git switch master
7077 $ git tag -a vX.Y.Z -m "Tagging version X.Y.Z"
7178
7279 - Push the previous commits and tag to the github repo::
170170
171171
172172 void do_bench(char *compressor, char *shuffle, int nthreads, int size, int elsize,
173 int rshift, int unsafe, FILE * ofile) {
173 int rshift, FILE * ofile) {
174174 void *src, *srccpy;
175175 void *dest[NCHUNKS], *dest2;
176176 int nbytes = 0, cbytes = 0;
214214 if (retcode) abort();
215215 }
216216
217 fprintf(ofile, "--> %d, %d, %d, %d, %s, %s, %s\n", nthreads, size, elsize,
218 rshift, compressor, shuffle, unsafe ? "unsafe" : "safe");
217 fprintf(ofile, "--> %d, %d, %d, %d, %s, %s\n", nthreads, size, elsize,
218 rshift, compressor, shuffle);
219219 fprintf(ofile, "********************** Run info ******************************\n");
220220 fprintf(ofile, "Blosc version: %s (%s)\n", BLOSC_VERSION_STRING, BLOSC_VERSION_DATE);
221221 fprintf(ofile, "Using synthetic data with %d significant bits (out of 32)\n", rshift);
222222 fprintf(ofile, "Dataset size: %d bytes\tType size: %d bytes\n", size, elsize);
223 fprintf(ofile, "Working set: %.1f MB\t\t", (size*nchunks) / (float)MB);
223 fprintf(ofile, "Working set: %.1f MB\t\t", (size * nchunks) / (float)MB);
224224 fprintf(ofile, "Number of threads: %d\n", nthreads);
225225 fprintf(ofile, "********************** Running benchmarks *********************\n");
226226
282282 nbytes = size;
283283 }
284284 else {
285 nbytes = unsafe ? blosc_decompress_unsafe(dest[j], dest2, size)
286 : blosc_decompress(dest[j], dest2, size);
285 nbytes = blosc_decompress(dest[j], dest2, size);
287286 }
288287 }
289288 }
377376 int extreme_suite = 0;
378377 int debug_suite = 0;
379378 int nthreads = 4; /* The number of threads */
380 int size = 2*MB; /* Buffer size */
379 int size = 4 * MB; /* Buffer size */
381380 int elsize = 8; /* Datatype size */
382381 int rshift = 19; /* Significant bits */
383 int workingset = 256*MB; /* The maximum allocated memory */
382 int workingset = 256 * MB; /* The maximum allocated memory */
384383 int nthreads_, size_, elsize_, rshift_, i;
385 int unsafe = 1;
386384 FILE * output_file = stdout;
387385 blosc_timestamp_t last, current;
388386 float totaltime;
393391 strncpy(usage, "Usage: bench [blosclz | lz4 | lz4hc | snappy | zlib | zstd] "
394392 "[noshuffle | shuffle | bitshuffle] "
395393 "[single | suite | hardsuite | extremesuite | debugsuite] "
396 "[nthreads] [bufsize(bytes)] [typesize] [sbits] [unsafe | safe]", 255);
394 "[nthreads] [bufsize(bytes)] [typesize] [sbits]", 255);
397395
398396 if (argc < 2) {
399397 printf("%s\n", usage);
491489 rshift = atoi(argv[7]);
492490 }
493491
494 if (argc >= 9) {
495 if (strcmp(argv[8], "unsafe") == 0) {
496 unsafe = 1;
497 } else if (strcmp(argv[8], "safe") == 0) {
498 unsafe = 0;
499 } else {
500 printf("%s\n", usage);
501 exit(1);
502 }
503 }
504
505 if ((argc >= 10) || !(single || suite || hard_suite || extreme_suite)) {
492 if ((argc >= 9) || !(single || suite || hard_suite || extreme_suite)) {
506493 printf("%s\n", usage);
507494 exit(1);
508495 }
514501
515502 if (suite) {
516503 for (nthreads_=1; nthreads_ <= nthreads; nthreads_++) {
517 do_bench(compressor, shuffle, nthreads_, size, elsize, rshift, unsafe, output_file);
504 do_bench(compressor, shuffle, nthreads_, size, elsize, rshift, output_file);
518505 }
519506 }
520507 else if (hard_suite) {
529516 nchunks = get_nchunks(size_+i, workingset);
530517 niter = 1;
531518 for (nthreads_ = 1; nthreads_ <= nthreads; nthreads_++) {
532 do_bench(compressor, shuffle, nthreads_, size_+i, elsize_, rshift_, unsafe, output_file);
519 do_bench(compressor, shuffle, nthreads_, size_+i, elsize_, rshift_, output_file);
533520 blosc_set_timestamp(&current);
534521 totaltime = (float)getseconds(last, current);
535522 printf("Elapsed time:\t %6.1f s. Processed data: %.1f GB\n",
548535 for (size_ = 32*KB; size_ <= size; size_ *= 2) {
549536 nchunks = get_nchunks(size_+i, workingset);
550537 for (nthreads_ = 1; nthreads_ <= nthreads; nthreads_++) {
551 do_bench(compressor, shuffle, nthreads_, size_+i, elsize_, rshift_, unsafe, output_file);
538 do_bench(compressor, shuffle, nthreads_, size_+i, elsize_, rshift_, output_file);
552539 blosc_set_timestamp(&current);
553540 totaltime = (float)getseconds(last, current);
554541 printf("Elapsed time:\t %6.1f s. Processed data: %.1f GB\n",
567554 for (size_ = size; size_ <= 16*MB; size_ *= 2) {
568555 nchunks = get_nchunks(size_+i, workingset);
569556 for (nthreads_ = nthreads; nthreads_ <= 6; nthreads_++) {
570 do_bench(compressor, shuffle, nthreads_, size_+i, elsize_, rshift_, unsafe, output_file);
557 do_bench(compressor, shuffle, nthreads_, size_+i, elsize_, rshift_, output_file);
571558 blosc_set_timestamp(&current);
572559 totaltime = (float)getseconds(last, current);
573560 printf("Elapsed time:\t %6.1f s. Processed data: %.1f GB\n",
580567 }
581568 /* Single mode */
582569 else {
583 do_bench(compressor, shuffle, nthreads, size, elsize, rshift, unsafe, output_file);
570 do_bench(compressor, shuffle, nthreads, size, elsize, rshift, output_file);
584571 }
585572
586573 /* Print out some statistics */
2828 tmp = line.split('-->')[1]
2929 parts = tmp.split(', ')
3030 nthreads, size, elsize, sbits, codec, shuffle = parts[:6]
31 safe = 'unsafe'
32 if len(parts) > 6:
33 safe = parts[6]
3431 nthreads, size, elsize, sbits = map(int, (nthreads, size, elsize, sbits))
35 values["size"] = size * NCHUNKS / MB_
32 values["size"] = size / MB_
3633 values["elsize"] = elsize
3734 values["sbits"] = sbits
3835 values["codec"] = codec
3936 values["shuffle"] = shuffle
40 values["safe"] = safe
4137 # New run for nthreads
4238 (ratios, speedsw, speedsr) = ([], [], [])
4339 # Add a new entry for (ratios, speedw, speedr)
4642 elif line.startswith('memcpy(write):'):
4743 tmp = line.split(',')[1]
4844 memcpyw = float(tmp.split(' ')[1])
49 values["memcpyw"].append(memcpyw)
45 values["memcpyw"].append(memcpyw / 1024)
5046 elif line.startswith('memcpy(read):'):
5147 tmp = line.split(',')[1]
5248 memcpyr = float(tmp.split(' ')[1])
53 values["memcpyr"].append(memcpyr)
49 values["memcpyr"].append(memcpyr / 1024)
5450 elif line.startswith('comp(write):'):
5551 tmp = line.split(',')[1]
5652 speedw = float(tmp.split(' ')[1])
5753 ratio = float(line.split(':')[-1])
58 speedsw.append(speedw)
54 speedsw.append(speedw / 1024)
5955 ratios.append(ratio)
6056 elif line.startswith('decomp(read):'):
6157 tmp = line.split(',')[1]
6258 speedr = float(tmp.split(' ')[1])
63 speedsr.append(speedr)
59 speedsr.append(speedr / 1024)
6460 if "OK" not in line:
6561 print("WARNING! OK not found in decomp line!")
6662
7066
7167 def show_plot(plots, yaxis, legends, gtitle, xmax=None, ymax=None):
7268 xlabel('Compresssion ratio')
73 ylabel('Speed (MB/s)')
69 ylabel('Speed (GB/s)')
7470 title(gtitle)
7571 xlim(0, xmax)
7672 ylim(0, ymax)
189185 if options.title:
190186 plot_title = options.title
191187 else:
192 plot_title += " (%(size).1f MB, %(elsize)d bytes, %(sbits)d bits), %(codec)s %(shuffle)s %(safe)s" % values
188 plot_title += " (%(size).1f MB, %(elsize)d bytes, %(sbits)d bits), %(codec)s %(shuffle)s" % values
193189
194190 gtitle = plot_title
195191
218214 mean = np.mean(values["memcpyr"])
219215 message = "memcpy (read from memory)"
220216 plot_ = axhline(mean, linewidth=3, linestyle='-.', color='black')
221 text(4.0, mean+400, message)
217 text(4.0, mean+.4, message)
222218 plots.append(plot_)
223219 show_plot(plots, yaxis, legends, gtitle,
224220 xmax=int(options.xmax) if options.xmax else None,
4040 if (ZSTD_FOUND)
4141 set(BLOSC_INCLUDE_DIRS ${BLOSC_INCLUDE_DIRS} ${ZSTD_INCLUDE_DIR})
4242 else (ZSTD_FOUND)
43 set(ZSTD_LOCAL_DIR ${INTERNAL_LIBS}/zstd-1.4.4)
43 set(ZSTD_LOCAL_DIR ${INTERNAL_LIBS}/zstd-1.4.5)
4444 set(BLOSC_INCLUDE_DIRS ${BLOSC_INCLUDE_DIRS} ${ZSTD_LOCAL_DIR} ${ZSTD_LOCAL_DIR}/common)
4545 endif (ZSTD_FOUND)
4646 endif (NOT DEACTIVATE_ZSTD)
8585 else(LZ4_FOUND)
8686 file(GLOB LZ4_FILES ${LZ4_LOCAL_DIR}/*.c)
8787 set(SOURCES ${SOURCES} ${LZ4_FILES})
88 source_group("LZ4" FILES ${LZ4_FILES})
8889 endif(LZ4_FOUND)
8990 endif(NOT DEACTIVATE_LZ4)
9091
9495 else(SNAPPY_FOUND)
9596 file(GLOB SNAPPY_FILES ${SNAPPY_LOCAL_DIR}/*.cc)
9697 set(SOURCES ${SOURCES} ${SNAPPY_FILES})
98 source_group("Snappy" FILES ${SNAPPY_FILES})
9799 endif(SNAPPY_FOUND)
98100 endif(NOT DEACTIVATE_SNAPPY)
99101
103105 else(ZLIB_FOUND)
104106 file(GLOB ZLIB_FILES ${ZLIB_LOCAL_DIR}/*.c)
105107 set(SOURCES ${SOURCES} ${ZLIB_FILES})
108 source_group("Zlib" FILES ${ZLIB_FILES})
106109 endif(ZLIB_FOUND)
107110 endif(NOT DEACTIVATE_ZLIB)
108111
115118 ${ZSTD_LOCAL_DIR}/compress/*.c
116119 ${ZSTD_LOCAL_DIR}/decompress/*.c)
117120 set(SOURCES ${SOURCES} ${ZSTD_FILES})
121 source_group("Zstd" FILES ${ZSTD_FILES})
118122 endif (ZSTD_FOUND)
119123 endif (NOT DEACTIVATE_ZSTD)
120124
1111 #include "blosc-export.h"
1212 #include <string.h>
1313
14 #ifdef __GNUC__
15 #define BLOSC_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
16 #endif // __GNUC__
17
1418 /* Import standard integer type definitions */
1519 #if defined(_WIN32) && !defined(__MINGW32__)
16
1720 /* stdint.h only available in VS2010 (VC++ 16.0) and newer */
1821 #if defined(_MSC_VER) && _MSC_VER < 1600
1922 #include "win32/stdint-windows.h"
422422 char* output, size_t maxout, int clevel)
423423 {
424424 int cbytes;
425 if (input_length > (size_t)(2<<30))
426 return -1; /* input larger than 1 GB is not supported */
425 if (input_length > (size_t)(UINT32_C(2)<<30))
426 return -1; /* input larger than 2 GB is not supported */
427427 /* clevel for lz4hc goes up to 12, at least in LZ4 1.7.5
428 * but levels larger than 9 does not buy much compression. */
428 * but levels larger than 9 do not buy much compression. */
429429 cbytes = LZ4_compress_HC(input, output, (int)input_length, (int)maxout,
430430 clevel);
431431 return cbytes;
521521 }
522522 #endif /* HAVE_ZSTD */
523523
524 static int initialize_decompress_func(struct blosc_context* context,
525 int unsafe) {
524 static int initialize_decompress_func(struct blosc_context* context) {
526525 int8_t header_flags = *(context->header_flags);
527526 int32_t compformat = (header_flags & 0xe0) >> 5;
528527 int compversion = context->compversion;
531530 if (compversion != BLOSC_BLOSCLZ_VERSION_FORMAT) {
532531 return -9;
533532 }
534 context->decompress_func =
535 unsafe ? &blosclz_decompress_unsafe : &blosclz_decompress;
533 context->decompress_func = &blosclz_decompress;
536534 return 0;
537535 }
538536 #if defined(HAVE_LZ4)
651649 }
652650 }
653651 if (context->compcode == BLOSC_BLOSCLZ) {
654 int doshuffle = (*(context->header_flags) & BLOSC_DOSHUFFLE) && (typesize > 1);
655652 cbytes = blosclz_compress(context->clevel, _tmp+j*neblock, neblock,
656 dest, maxout, doshuffle);
653 dest, maxout);
657654 }
658655 #if defined(HAVE_LZ4)
659656 else if (context->compcode == BLOSC_LZ4) {
711708 if ((ntbytes+neblock) > maxbytes) {
712709 return 0; /* Non-compressible data */
713710 }
714 blosc_internal_fastcopy(dest, _tmp + j * neblock, neblock);
711 fastcopy(dest, _tmp + j * neblock, neblock);
715712 cbytes = neblock;
716713 }
717714 _sw32(dest - 4, cbytes);
775772 src = base_src + src_offset;
776773 /* Uncompress */
777774 if (cbytes == neblock) {
778 blosc_internal_fastcopy(_tmp, src, neblock);
775 fastcopy(_tmp, src, neblock);
779776 nbytes = neblock;
780777 }
781778 else {
829826 if (context->compress) {
830827 if (*(context->header_flags) & BLOSC_MEMCPYED) {
831828 /* We want to memcpy only */
832 blosc_internal_fastcopy(context->dest + BLOSC_MAX_OVERHEAD + j * context->blocksize,
833 context->src + j * context->blocksize, bsize);
829 fastcopy(context->dest + BLOSC_MAX_OVERHEAD + j * context->blocksize,
830 context->src + j * context->blocksize, bsize);
834831 cbytes = bsize;
835832 }
836833 else {
847844 else {
848845 if (*(context->header_flags) & BLOSC_MEMCPYED) {
849846 /* We want to memcpy only */
850 blosc_internal_fastcopy(context->dest + j * context->blocksize,
851 context->src + BLOSC_MAX_OVERHEAD + j * context->blocksize, bsize);
847 fastcopy(context->dest + j * context->blocksize,
848 context->src + BLOSC_MAX_OVERHEAD + j * context->blocksize, bsize);
852849 cbytes = bsize;
853850 }
854851 else {
879876 (void)rc; // just to avoid 'unused-variable' warning
880877
881878 /* Check whether we need to restart threads */
882 blosc_set_nthreads_(context);
879 if (blosc_set_nthreads_(context) < 0) {
880 return -1;
881 }
883882
884883 /* Set sentinels */
885884 context->thread_giveup_code = 1;
10331032
10341033 /* Enlarge the blocksize for splittable codecs */
10351034 if (clevel > 0 && split_block(context->compcode, typesize, blocksize)) {
1036 if (blocksize > (1 << 16)) {
1037 /* Do not use a too large split buffer (> 64 KB) for splitting codecs */
1038 blocksize = (1 << 16);
1035 if (blocksize > (1 << 18)) {
1036 /* Do not use a too large split buffer (> 256 KB) for splitting codecs */
1037 blocksize = (1 << 18);
10391038 }
10401039 blocksize *= typesize;
10411040 if (blocksize < (1 << 16)) {
10421041 /* Do not use a too small blocksize (< 64 KB) when typesize is small */
10431042 blocksize = (1 << 16);
10441043 }
1044 if (blocksize > 1024 * 1024) {
1045 /* But do not exceed 1 MB per thread (having this capacity in L3 is normal in modern CPUs) */
1046 blocksize = 1024 * 1024;
1047 }
1048
10451049 }
10461050
10471051 /* Check that blocksize is not too large */
10691073 int32_t blocksize,
10701074 int32_t numthreads)
10711075 {
1076 char *envvar = NULL;
1077 int warnlvl = 0;
10721078 /* Set parameters */
10731079 context->compress = 1;
10741080 context->src = (const uint8_t*)src;
10821088 context->end_threads = 0;
10831089 context->clevel = clevel;
10841090
1091 envvar = getenv("BLOSC_WARN");
1092 if (envvar != NULL) {
1093 warnlvl = strtol(envvar, NULL, 10);
1094 }
1095
10851096 /* Check buffer size limits */
10861097 if (sourcesize > BLOSC_MAX_BUFFERSIZE) {
1087 fprintf(stderr, "Input buffer size cannot exceed %d bytes\n",
1088 BLOSC_MAX_BUFFERSIZE);
1089 return -1;
1098 if (warnlvl > 0) {
1099 fprintf(stderr, "Input buffer size cannot exceed %d bytes\n",
1100 BLOSC_MAX_BUFFERSIZE);
1101 }
1102 return 0;
10901103 }
10911104 if (destsize < BLOSC_MAX_OVERHEAD) {
1092 fprintf(stderr, "Output buffer size should be larger than %d bytes\n",
1093 BLOSC_MAX_OVERHEAD);
1094 return -1;
1105 if (warnlvl > 0) {
1106 fprintf(stderr, "Output buffer size should be larger than %d bytes\n",
1107 BLOSC_MAX_OVERHEAD);
1108 }
1109 return 0;
10951110 }
10961111
10971112 /* Compression level */
10981113 if (clevel < 0 || clevel > 9) {
1099 /* If clevel not in 0..9, print an error */
11001114 fprintf(stderr, "`clevel` parameter must be between 0 and 9!\n");
11011115 return -10;
11021116 }
12721286 nbytes, src, dest, destsize,
12731287 blosc_compname_to_compcode(compressor),
12741288 blocksize, numinternalthreads);
1275 if (error < 0) { return error; }
1289 if (error <= 0) { return error; }
12761290
12771291 error = write_compression_header(&context, clevel, doshuffle);
1278 if (error < 0) { return error; }
1292 if (error <= 0) { return error; }
12791293
12801294 result = blosc_compress_context(&context);
12811295
13941408 typesize, nbytes, src, dest, destsize,
13951409 g_compressor, g_force_blocksize,
13961410 g_threads);
1397 if (result < 0) { break; }
1411 if (result <= 0) { break; }
13981412
13991413 result = write_compression_header(g_global_context, clevel, doshuffle);
1400 if (result < 0) { break; }
1414 if (result <= 0) { break; }
14011415
14021416 result = blosc_compress_context(g_global_context);
14031417 } while (0);
14111425 const void* src,
14121426 void* dest,
14131427 size_t destsize,
1414 int numinternalthreads,
1415 int unsafe)
1428 int numinternalthreads)
14161429 {
14171430 uint8_t version;
14181431 int32_t ntbytes;
14741487 return -1;
14751488 }
14761489 } else {
1477 ntbytes = initialize_decompress_func(context, unsafe);
1490 ntbytes = initialize_decompress_func(context);
14781491 if (ntbytes != 0) return ntbytes;
14791492
14801493 /* Validate that compressed size is large enough to hold the bstarts array */
14931506 return ntbytes;
14941507 }
14951508
1496 /* Implementation of blosc_decompress_ctx{,_unsafe}. */
1497 static int blosc_decompress_ctx_impl(const void* src, void* dest,
1498 size_t destsize, int numinternalthreads,
1499 int unsafe) {
1509 int blosc_decompress_ctx(const void* src, void* dest, size_t destsize,
1510 int numinternalthreads) {
15001511 int result;
15011512 struct blosc_context context;
15021513
15031514 context.threads_started = 0;
15041515 result = blosc_run_decompression_with_context(&context, src, dest, destsize,
1505 numinternalthreads, unsafe);
1516 numinternalthreads);
15061517
15071518 if (numinternalthreads > 1)
15081519 {
15121523 return result;
15131524 }
15141525
1515 int blosc_decompress_ctx(const void* src, void* dest, size_t destsize,
1516 int numinternalthreads) {
1517 return blosc_decompress_ctx_impl(src, dest, destsize, numinternalthreads,
1518 /*unsafe=*/0);
1519 }
1520
1521 int blosc_decompress_ctx_unsafe(const void* src, void* dest, size_t destsize,
1522 int numinternalthreads) {
1523 return blosc_decompress_ctx_impl(src, dest, destsize, numinternalthreads,
1524 /*unsafe=*/1);
1525 }
1526
1527 /* Implementation of blosc_decompress{,_unsafe}. */
1528 static int blosc_decompress_impl(const void* src, void* dest,
1529 size_t destsize, int unsafe) {
1526 int blosc_decompress(const void* src, void* dest, size_t destsize) {
15301527 int result;
15311528 char* envvar;
15321529 long nthreads;
15561553 pthread_mutex_lock(global_comp_mutex);
15571554
15581555 result = blosc_run_decompression_with_context(g_global_context, src, dest,
1559 destsize, g_threads, unsafe);
1556 destsize, g_threads);
15601557
15611558 pthread_mutex_unlock(global_comp_mutex);
15621559
15631560 return result;
15641561 }
15651562
1566 /* The public routine for decompression. See blosc.h for docstrings. */
1567 int blosc_decompress(const void *src, void *dest, size_t destsize) {
1568 return blosc_decompress_impl(src, dest, destsize, /*unsafe=*/0);
1569 }
1570
1571 int blosc_decompress_unsafe(const void *src, void *dest, size_t destsize) {
1572 return blosc_decompress_impl(src, dest, destsize, /*unsafe=*/1);
1573 }
1574
1575
1576 /* Implementation of blosc_getitem{,_unsafe}. */
1577 static int blosc_getitem_impl(const void* src, int start, int nitems,
1578 void* dest, int unsafe) {
1563 int blosc_getitem(const void* src, int start, int nitems, void* dest) {
15791564 uint8_t *_src=NULL; /* current pos for source buffer */
15801565 uint8_t version, compversion; /* versions for compressed header */
15811566 uint8_t flags; /* flags for header */
16281613 return -1;
16291614 }
16301615 } else {
1631 ntbytes = initialize_decompress_func(&context, /*unsafe=*/unsafe);
1616 ntbytes = initialize_decompress_func(&context);
16321617 if (ntbytes != 0) return ntbytes;
16331618
16341619 if (nblocks >= (compressedsize - 16) / 4) {
16811666 /* Do the actual data copy */
16821667 if (flags & BLOSC_MEMCPYED) {
16831668 /* We want to memcpy only */
1684 blosc_internal_fastcopy((uint8_t *) dest + ntbytes,
1685 (uint8_t *) src + BLOSC_MAX_OVERHEAD + j * blocksize + startb, bsize2);
1669 fastcopy((uint8_t *) dest + ntbytes,
1670 (uint8_t *) src + BLOSC_MAX_OVERHEAD + j * blocksize + startb, bsize2);
16861671 cbytes = bsize2;
16871672 }
16881673 else {
16951680 break;
16961681 }
16971682 /* Copy to destination */
1698 blosc_internal_fastcopy((uint8_t *) dest + ntbytes, tmp2 + startb, bsize2);
1683 fastcopy((uint8_t *) dest + ntbytes, tmp2 + startb, bsize2);
16991684 cbytes = bsize2;
17001685 }
17011686 ntbytes += cbytes;
17041689 my_free(tmp);
17051690
17061691 return ntbytes;
1707 }
1708
1709 /* Specific routine optimized for decompression a small number of
1710 items out of a compressed chunk. This does not use threads because
1711 it would affect negatively to performance. */
1712 int blosc_getitem(const void *src, int start, int nitems, void *dest) {
1713 return blosc_getitem_impl(src, start, nitems, dest, /*unsafe=*/0);
1714 }
1715
1716 int blosc_getitem_unsafe(const void *src, int start, int nitems, void *dest) {
1717 return blosc_getitem_impl(src, start, nitems, dest, /*unsafe=*/1);
17181692 }
17191693
17201694 /* Decompress & unshuffle several blocks in a single thread */
18161790 if (compress) {
18171791 if (flags & BLOSC_MEMCPYED) {
18181792 /* We want to memcpy only */
1819 blosc_internal_fastcopy(dest + BLOSC_MAX_OVERHEAD + nblock_ * blocksize, src + nblock_ * blocksize,
1820 bsize);
1793 fastcopy(dest + BLOSC_MAX_OVERHEAD + nblock_ * blocksize,
1794 src + nblock_ * blocksize, bsize);
18211795 cbytes = bsize;
18221796 }
18231797 else {
18291803 else {
18301804 if (flags & BLOSC_MEMCPYED) {
18311805 /* We want to memcpy only */
1832 blosc_internal_fastcopy(dest + nblock_ * blocksize, src + BLOSC_MAX_OVERHEAD + nblock_ * blocksize,
1833 bsize);
1806 fastcopy(dest + nblock_ * blocksize,
1807 src + BLOSC_MAX_OVERHEAD + nblock_ * blocksize, bsize);
18341808 cbytes = bsize;
18351809 }
18361810 else {
18721846 /* End of critical section */
18731847
18741848 /* Copy the compressed buffer to destination */
1875 blosc_internal_fastcopy(dest + ntdest, tmp2, cbytes);
1849 fastcopy(dest + ntdest, tmp2, cbytes);
18761850 }
18771851 else {
18781852 nblock_++;
20031977 /* Launch a new pool of threads */
20041978 if (context->numthreads > 1 && context->numthreads != context->threads_started) {
20051979 blosc_release_threadpool(context);
2006 init_threads(context);
1980 if (init_threads(context) < 0) {
1981 return -1;
1982 }
20071983 }
20081984
20091985 /* We have now started the threads */
1717
1818 /* Version numbers */
1919 #define BLOSC_VERSION_MAJOR 1 /* for major interface/format changes */
20 #define BLOSC_VERSION_MINOR 17 /* for minor interface/format changes */
20 #define BLOSC_VERSION_MINOR 20 /* for minor interface/format changes */
2121 #define BLOSC_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */
2222
23 #define BLOSC_VERSION_STRING "1.17.1" /* string version. Sync with above! */
23 #define BLOSC_VERSION_STRING "1.20.1" /* string version. Sync with above! */
2424 #define BLOSC_VERSION_REVISION "$Rev$" /* revision version */
25 #define BLOSC_VERSION_DATE "$Date:: 2019-12-12 #$" /* date version */
26
27 #define BLOSCLZ_VERSION_STRING "2.0.0" /* the internal compressor version */
25 #define BLOSC_VERSION_DATE "$Date:: 2020-09-08 #$" /* date version */
26
27 #define BLOSCLZ_VERSION_STRING "2.3.0" /* the internal compressor version */
2828
2929 /* The *_FORMAT symbols should be just 1-byte long */
3030 #define BLOSC_VERSION_FORMAT 2 /* Blosc format version, starting at 1 */
214214 This will call blosc_set_splitmode() with the different supported values.
215215 See blosc_set_splitmode() docstrings for more info on each mode.
216216
217 BLOSC_WARN=(INTEGER): This will print some warning message on stderr
218 showing more info in situations where data inputs cannot be compressed.
219 The values can range from 1 (less verbose) to 10 (full verbose). 0 is
220 the same as if the BLOSC_WARN envvar was not defined.
217221 */
218222 BLOSC_EXPORT int blosc_compress(int clevel, int doshuffle, size_t typesize,
219223 size_t nbytes, const void *src, void *dest,
277281 BLOSC_EXPORT int blosc_decompress(const void *src, void *dest, size_t destsize);
278282
279283 /**
280 Same as `blosc_decompress`, except that this is not safe to run on
281 untrusted/possibly corrupted input (even after calling
282 `blosc_cbuffer_validate`).
283
284 This may be marginally faster than `blosc_decompress` due to skipping certain
285 bounds checking and validation.
286 */
287 BLOSC_EXPORT int blosc_decompress_unsafe(const void* src, void* dest,
288 size_t destsize);
289
290 /**
291284 Context interface to blosc decompression. This does not require a
292285 call to blosc_init() and can be called from multithreaded
293286 applications without the global lock being used, so allowing Blosc
310303 size_t destsize, int numinternalthreads);
311304
312305 /**
313 Same as `blosc_decompress_ctx`, except that this is not safe to run on
314 untrusted/possibly corrupted input (even after calling
315 `blosc_cbuffer_validate`).
316
317 This may be marginally faster than `blosc_decompress_ctx` due to skipping
318 certain bounds checking and validation.
319 */
320 BLOSC_EXPORT int blosc_decompress_ctx_unsafe(const void* src, void* dest,
321 size_t destsize,
322 int numinternalthreads);
323
324 /**
325306 Get `nitems` (of typesize size) in `src` buffer starting in `start`.
326307 The items are returned in `dest` buffer, which has to have enough
327308 space for storing all items.
330311 some error happens.
331312 */
332313 BLOSC_EXPORT int blosc_getitem(const void *src, int start, int nitems, void *dest);
333
334 /**
335 Same as `blosc_getitem`, except that this is not safe to run on
336 untrusted/possibly corrupted input (even after calling
337 `blosc_cbuffer_validate`).
338
339 This may be marginally faster than `blosc_getitem` due to skipping certain
340 bounds checking and validation.
341 */
342 BLOSC_EXPORT int blosc_getitem_unsafe(const void* src, int start, int nitems,
343 void* dest);
344314
345315 /**
346316 Returns the current number of threads that are used for
368338
369339 /**
370340 Select the compressor to be used. The supported ones are "blosclz",
371 "lz4", "lz4hc", "snappy", "zlib" and "ztsd". If this function is not
341 "lz4", "lz4hc", "snappy", "zlib" and "zstd". If this function is not
372342 called, then "blosclz" will be used by default.
373343
374344 In case the compressor is not recognized, or there is not support
33 Author: Francesc Alted <francesc@blosc.org>
44 Creation date: 2009-05-20
55
6 See LICENSES/BLOSC.txt for details about copyright and rights to use.
6 See LICENSE.txt for details about copyright and rights to use.
77 **********************************************************************/
88
99 /*********************************************************************
1313
1414
1515 #include <stdio.h>
16 #include <stdlib.h>
17
18 #if defined(_WIN32) && !defined(__MINGW32__)
19 #include <windows.h>
20 /* stdint.h only available in VS2010 (VC++ 16.0) and newer */
21 #if defined(_MSC_VER) && _MSC_VER < 1600
22 #include "win32/stdint-windows.h"
23 #else
24 #include <stdint.h>
25 #endif
26 #else
27 #include <stdint.h>
28 #endif /* _WIN32 */
29
16 #include <stdbool.h>
3017 #include "blosclz.h"
3118 #include "fastcopy.h"
3219 #include "blosc-common.h"
33 #include "blosc-comp-features.h"
3420
3521
3622 /*
3723 * Give hints to the compiler for branch prediction optimization.
3824 */
3925 #if defined(__GNUC__) && (__GNUC__ > 2)
40 #define BLOSCLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1))
41 #define BLOSCLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0))
26 #define BLOSCLZ_LIKELY(c) (__builtin_expect((c), 1))
27 #define BLOSCLZ_UNLIKELY(c) (__builtin_expect((c), 0))
4228 #else
43 #define BLOSCLZ_EXPECT_CONDITIONAL(c) (c)
44 #define BLOSCLZ_UNEXPECT_CONDITIONAL(c) (c)
29 #define BLOSCLZ_LIKELY(c) (c)
30 #define BLOSCLZ_UNLIKELY(c) (c)
4531 #endif
4632
4733 /*
5642 #define MAX_FARDISTANCE (65535 + MAX_DISTANCE - 1)
5743
5844 #ifdef BLOSC_STRICT_ALIGN
59 #define BLOSCLZ_READU16(p) ((p)[0] | (p)[1]<<8)
45 #define BLOSCLZ_READU16(p) ((p)[0] | (p)[1]<<8)
6046 #define BLOSCLZ_READU32(p) ((p)[0] | (p)[1]<<8 | (p)[2]<<16 | (p)[3]<<24)
6147 #else
62 #define BLOSCLZ_READU16(p) *((const uint16_t*)(p))
63 #define BLOSCLZ_READU32(p) *((const uint32_t*)(p))
64 #endif
65
66 #define HASH_LOG (14U)
67
68 /* Simple, but pretty effective hash function for 3-byte sequence */
69 // This is the original hash function used in fastlz
70 //#define HASH_FUNCTION(v, p, h) { \
71 // v = BLOSCLZ_READU16(p); \
72 // v ^= BLOSCLZ_READU16(p + 1) ^ ( v >> (16 - h)); \
73 // v &= (1 << h) - 1; \
74 //}
48 #define BLOSCLZ_READU16(p) *((const uint16_t*)(p))
49 #define BLOSCLZ_READU32(p) *((const uint32_t*)(p))
50 #endif
51
52 #define HASH_LOG (12U)
7553
7654 // This is used in LZ4 and seems to work pretty well here too
77 #define HASH_FUNCTION(v, p, h) \
78 v = ((BLOSCLZ_READU32(p) * 2654435761U) >> (32U - h))
79
80
81 #define LITERAL(ip, op, op_limit, anchor, copy) { \
82 if (BLOSCLZ_UNEXPECT_CONDITIONAL(op + 2 > op_limit)) \
83 goto out; \
84 *op++ = *anchor++; \
85 ip = anchor; \
86 copy++; \
87 if (BLOSCLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) { \
88 copy = 0; \
89 *op++ = MAX_COPY-1; \
90 nmax_copies++; \
91 if (nmax_copies > max_nmax_copies) \
92 goto out; \
93 } \
94 continue; \
95 }
96
97 #define IP_BOUNDARY 2
98
55 #define HASH_FUNCTION(v, s, h) { \
56 v = (s * 2654435761U) >> (32U - h); \
57 }
58
59
60 #if defined(__AVX2__)
61 static uint8_t *get_run_32(uint8_t *ip, const uint8_t *ip_bound, const uint8_t *ref) {
62 uint8_t x = ip[-1];
63 /* safe because the outer check against ip limit */
64 if (ip < (ip_bound - sizeof(int64_t))) {
65 int64_t value, value2;
66 /* Broadcast the value for every byte in a 64-bit register */
67 memset(&value, x, 8);
68 #if defined(BLOSC_STRICT_ALIGN)
69 memcpy(&value2, ref, 8);
70 #else
71 value2 = ((int64_t*)ref)[0];
72 #endif
73 if (value != value2) {
74 /* Return the byte that starts to differ */
75 while (*ref++ == x) ip++;
76 return ip;
77 }
78 else {
79 ip += 8;
80 ref += 8;
81 }
82 }
83 if (ip < (ip_bound - sizeof(__m128i))) {
84 __m128i value, value2, cmp;
85 /* Broadcast the value for every byte in a 128-bit register */
86 memset(&value, x, sizeof(__m128i));
87 value2 = _mm_loadu_si128((__m128i *) ref);
88 cmp = _mm_cmpeq_epi32(value, value2);
89 if (_mm_movemask_epi8(cmp) != 0xFFFF) {
90 /* Return the byte that starts to differ */
91 while (*ref++ == x) ip++;
92 return ip;
93 } else {
94 ip += sizeof(__m128i);
95 ref += sizeof(__m128i);
96 }
97 }
98 while (ip < (ip_bound - (sizeof(__m256i)))) {
99 __m256i value, value2, cmp;
100 /* Broadcast the value for every byte in a 256-bit register */
101 memset(&value, x, sizeof(__m256i));
102 value2 = _mm256_loadu_si256((__m256i *)ref);
103 cmp = _mm256_cmpeq_epi64(value, value2);
104 if ((unsigned)_mm256_movemask_epi8(cmp) != 0xFFFFFFFF) {
105 /* Return the byte that starts to differ */
106 while (*ref++ == x) ip++;
107 return ip;
108 }
109 else {
110 ip += sizeof(__m256i);
111 ref += sizeof(__m256i);
112 }
113 }
114 /* Look into the remainder */
115 while ((ip < ip_bound) && (*ref++ == x)) ip++;
116 return ip;
117 }
118
119 #elif defined(__SSE2__)
120
121 static uint8_t *get_run_16(uint8_t *ip, const uint8_t *ip_bound, const uint8_t *ref) {
122 uint8_t x = ip[-1];
123
124 if (ip < (ip_bound - sizeof(int64_t))) {
125 int64_t value, value2;
126 /* Broadcast the value for every byte in a 64-bit register */
127 memset(&value, x, 8);
128 #if defined(BLOSC_STRICT_ALIGN)
129 memcpy(&value2, ref, 8);
130 #else
131 value2 = ((int64_t*)ref)[0];
132 #endif
133 if (value != value2) {
134 /* Return the byte that starts to differ */
135 while (*ref++ == x) ip++;
136 return ip;
137 }
138 else {
139 ip += 8;
140 ref += 8;
141 }
142 }
143 /* safe because the outer check against ip limit */
144 while (ip < (ip_bound - sizeof(__m128i))) {
145 __m128i value, value2, cmp;
146 /* Broadcast the value for every byte in a 128-bit register */
147 memset(&value, x, sizeof(__m128i));
148 value2 = _mm_loadu_si128((__m128i *)ref);
149 cmp = _mm_cmpeq_epi32(value, value2);
150 if (_mm_movemask_epi8(cmp) != 0xFFFF) {
151 /* Return the byte that starts to differ */
152 while (*ref++ == x) ip++;
153 return ip;
154 }
155 else {
156 ip += sizeof(__m128i);
157 ref += sizeof(__m128i);
158 }
159 }
160 /* Look into the remainder */
161 while ((ip < ip_bound) && (*ref++ == x)) ip++;
162 return ip;
163 }
164
165 #else
99166
100167 static uint8_t *get_run(uint8_t *ip, const uint8_t *ip_bound, const uint8_t *ref) {
101168 uint8_t x = ip[-1];
124191 return ip;
125192 }
126193
127 #ifdef __SSE2__
128 static uint8_t *get_run_16(uint8_t *ip, const uint8_t *ip_bound, const uint8_t *ref) {
129 uint8_t x = ip[-1];
130
131 if (ip < (ip_bound - sizeof(int64_t))) {
132 int64_t value, value2;
133 /* Broadcast the value for every byte in a 64-bit register */
134 memset(&value, x, 8);
135 #if defined(BLOSC_STRICT_ALIGN)
136 memcpy(&value2, ref, 8);
137 #else
138 value2 = ((int64_t*)ref)[0];
139 #endif
140 if (value != value2) {
141 /* Return the byte that starts to differ */
142 while (*ref++ == x) ip++;
143 return ip;
144 }
145 else {
146 ip += 8;
147 ref += 8;
148 }
149 }
150 /* safe because the outer check against ip limit */
151 while (ip < (ip_bound - sizeof(__m128i))) {
152 __m128i value, value2, cmp;
153 /* Broadcast the value for every byte in a 128-bit register */
154 memset(&value, x, sizeof(__m128i));
155 value2 = _mm_loadu_si128((__m128i *)ref);
156 cmp = _mm_cmpeq_epi32(value, value2);
157 if (_mm_movemask_epi8(cmp) != 0xFFFF) {
158 /* Return the byte that starts to differ */
159 while (*ref++ == x) ip++;
160 return ip;
161 }
162 else {
163 ip += sizeof(__m128i);
164 ref += sizeof(__m128i);
165 }
166 }
167 /* Look into the remainder */
168 while ((ip < ip_bound) && (*ref++ == x)) ip++;
169 return ip;
170 }
171 #endif
172
173
174 #ifdef __AVX2__
175 static uint8_t *get_run_32(uint8_t *ip, const uint8_t *ip_bound, const uint8_t *ref) {
176 uint8_t x = ip[-1];
177 /* safe because the outer check against ip limit */
178 if (ip < (ip_bound - sizeof(int64_t))) {
179 int64_t value, value2;
180 /* Broadcast the value for every byte in a 64-bit register */
181 memset(&value, x, 8);
182 #if defined(BLOSC_STRICT_ALIGN)
183 memcpy(&value2, ref, 8);
184 #else
185 value2 = ((int64_t*)ref)[0];
186 #endif
187 if (value != value2) {
188 /* Return the byte that starts to differ */
189 while (*ref++ == x) ip++;
190 return ip;
191 }
192 else {
193 ip += 8;
194 ref += 8;
195 }
196 }
197 if (ip < (ip_bound - sizeof(__m128i))) {
198 __m128i value, value2, cmp;
199 /* Broadcast the value for every byte in a 128-bit register */
200 memset(&value, x, sizeof(__m128i));
201 value2 = _mm_loadu_si128((__m128i *) ref);
202 cmp = _mm_cmpeq_epi32(value, value2);
203 if (_mm_movemask_epi8(cmp) != 0xFFFF) {
204 /* Return the byte that starts to differ */
205 while (*ref++ == x) ip++;
206 return ip;
207 } else {
208 ip += sizeof(__m128i);
209 ref += sizeof(__m128i);
210 }
211 }
212 while (ip < (ip_bound - (sizeof(__m256i)))) {
213 __m256i value, value2, cmp;
214 /* Broadcast the value for every byte in a 256-bit register */
215 memset(&value, x, sizeof(__m256i));
216 value2 = _mm256_loadu_si256((__m256i *)ref);
217 cmp = _mm256_cmpeq_epi64(value, value2);
218 if (_mm256_movemask_epi8(cmp) != 0xFFFFFFFF) {
219 /* Return the byte that starts to differ */
220 while (*ref++ == x) ip++;
221 return ip;
222 }
223 else {
224 ip += sizeof(__m256i);
225 ref += sizeof(__m256i);
226 }
227 }
228 /* Look into the remainder */
229 while ((ip < ip_bound) && (*ref++ == x)) ip++;
230 return ip;
231 }
232194 #endif
233195
234196
319281 value = _mm256_loadu_si256((__m256i *) ip);
320282 value2 = _mm256_loadu_si256((__m256i *)ref);
321283 cmp = _mm256_cmpeq_epi64(value, value2);
322 if (_mm256_movemask_epi8(cmp) != 0xFFFFFFFF) {
284 if ((unsigned)_mm256_movemask_epi8(cmp) != 0xFFFFFFFF) {
323285 /* Return the byte that starts to differ */
324286 while (*ref++ == *ip++) {}
325287 return ip;
336298 #endif
337299
338300
339 int blosclz_compress(const int opt_level, const void* input, int length,
340 void* output, int maxout, int shuffle) {
341 uint8_t* ip = (uint8_t*)input;
301 static uint8_t* get_run_or_match(uint8_t* ip, uint8_t* ip_bound, const uint8_t* ref, bool run) {
302 if (BLOSCLZ_UNLIKELY(run)) {
303 #if defined(__AVX2__)
304 ip = get_run_32(ip, ip_bound, ref);
305 #elif defined(__SSE2__)
306 ip = get_run_16(ip, ip_bound, ref);
307 #else
308 ip = get_run(ip, ip_bound, ref);
309 #endif
310 }
311 else {
312 #if defined(__AVX2__)
313 ip = get_match_32(ip, ip_bound, ref);
314 #elif defined(__SSE2__)
315 ip = get_match_16(ip, ip_bound, ref);
316 #else
317 ip = get_match(ip, ip_bound, ref);
318 #endif
319 }
320
321 return ip;
322 }
323
324
325 #define LITERAL(ip, op, op_limit, anchor, copy) { \
326 if (BLOSCLZ_UNLIKELY(op + 2 > op_limit)) \
327 goto out; \
328 *op++ = *anchor++; \
329 ip = anchor; \
330 copy++; \
331 if (BLOSCLZ_UNLIKELY(copy == MAX_COPY)) { \
332 copy = 0; \
333 *op++ = MAX_COPY-1; \
334 } \
335 }
336
337 #define LITERAL2(ip, oc, anchor, copy) { \
338 oc++; anchor++; \
339 ip = anchor; \
340 copy++; \
341 if (BLOSCLZ_UNLIKELY(copy == MAX_COPY)) { \
342 copy = 0; \
343 oc++; \
344 } \
345 }
346
347 #define DISTANCE_SHORT(op, op_limit, len, distance) { \
348 if (BLOSCLZ_UNLIKELY(op + 2 > op_limit)) \
349 goto out; \
350 *op++ = (uint8_t)((len << 5U) + (distance >> 8U)); \
351 *op++ = (uint8_t)((distance & 255U)); \
352 }
353
354 #define DISTANCE_LONG(op, op_limit, len, distance) { \
355 if (BLOSCLZ_UNLIKELY(op + 1 > op_limit)) \
356 goto out; \
357 *op++ = (uint8_t)((7U << 5U) + (distance >> 8U)); \
358 for (len -= 7; len >= 255; len -= 255) { \
359 if (BLOSCLZ_UNLIKELY(op + 1 > op_limit)) \
360 goto out; \
361 *op++ = 255; \
362 } \
363 if (BLOSCLZ_UNLIKELY(op + 2 > op_limit)) \
364 goto out; \
365 *op++ = (uint8_t)len; \
366 *op++ = (uint8_t)((distance & 255U)); \
367 }
368
369 #define DISTANCE_SHORT_FAR(op, op_limit, len, distance) { \
370 if (BLOSCLZ_UNLIKELY(op + 4 > op_limit)) \
371 goto out; \
372 *op++ = (uint8_t)((len << 5U) + 31); \
373 *op++ = 255; \
374 *op++ = (uint8_t)(distance >> 8U); \
375 *op++ = (uint8_t)(distance & 255U); \
376 }
377
378 #define DISTANCE_LONG_FAR(op, op_limit, len, distance) { \
379 if (BLOSCLZ_UNLIKELY(op + 1 > op_limit)) \
380 goto out; \
381 *op++ = (7U << 5U) + 31; \
382 for (len -= 7; len >= 255; len -= 255) { \
383 if (BLOSCLZ_UNLIKELY(op + 1 > op_limit)) \
384 goto out; \
385 *op++ = 255; \
386 } \
387 if (BLOSCLZ_UNLIKELY(op + 4 > op_limit)) \
388 goto out; \
389 *op++ = (uint8_t)len; \
390 *op++ = 255; \
391 *op++ = (uint8_t)(distance >> 8U); \
392 *op++ = (uint8_t)(distance & 255U); \
393 }
394
395
396 // Get the compressed size of a buffer. Useful for testing compression ratios for high clevels.
397 static int get_csize(uint8_t* ibase, int maxlen, bool force_3b_shift) {
398 uint8_t* ip = ibase;
399 int32_t oc = 0;
400 uint8_t* ip_bound = ibase + maxlen - 1;
401 uint8_t* ip_limit = ibase + maxlen - 12;
402 uint32_t htab[1U << (uint8_t)HASH_LOG];
403 uint32_t hval;
404 uint32_t seq;
405 uint8_t copy;
406
407 // Initialize the hash table to distances of 0
408 for (unsigned i = 0; i < (1U << HASH_LOG); i++) {
409 htab[i] = 0;
410 }
411
412 /* we start with literal copy */
413 copy = 4;
414 oc += 5;
415
416 /* main loop */
417 while (BLOSCLZ_LIKELY(ip < ip_limit)) {
418 const uint8_t* ref;
419 unsigned distance;
420 uint8_t* anchor = ip; /* comparison starting-point */
421
422 /* find potential match */
423 seq = BLOSCLZ_READU32(ip);
424 HASH_FUNCTION(hval, seq, HASH_LOG)
425 ref = ibase + htab[hval];
426
427 /* calculate distance to the match */
428 distance = anchor - ref;
429
430 /* update hash table */
431 htab[hval] = (uint32_t) (anchor - ibase);
432
433 if (distance == 0 || (distance >= MAX_FARDISTANCE)) {
434 LITERAL2(ip, oc, anchor, copy)
435 continue;
436 }
437
438 /* is this a match? check the first 4 bytes */
439 if (BLOSCLZ_UNLIKELY(BLOSCLZ_READU32(ref) == BLOSCLZ_READU32(ip))) {
440 ref += 4;
441 }
442 else {
443 /* no luck, copy as a literal */
444 LITERAL2(ip, oc, anchor, copy)
445 continue;
446 }
447
448 /* last matched byte */
449 ip = anchor + 4;
450
451 /* distance is biased */
452 distance--;
453
454 /* get runs or matches; zero distance means a run */
455 ip = get_run_or_match(ip, ip_bound, ref, !distance);
456
457 ip -= force_3b_shift ? 3 : 4;
458 unsigned len = (int)(ip - anchor);
459 // If match is close, let's reduce the minimum length to encode it
460 unsigned minlen = (distance < MAX_DISTANCE) ? 3 : 4;
461 // Encoding short lengths is expensive during decompression
462 if (len < minlen) {
463 LITERAL2(ip, oc, anchor, copy)
464 continue;
465 }
466
467 /* if we have'nt copied anything, adjust the output counter */
468 if (!copy)
469 oc--;
470 /* reset literal counter */
471 copy = 0;
472
473 /* encode the match */
474 if (distance < MAX_DISTANCE) {
475 if (len >= 7) {
476 oc += ((len - 7) / 255) + 1;
477 }
478 oc += 2;
479 }
480 else {
481 /* far away, but not yet in the another galaxy... */
482 if (len >= 7) {
483 oc += ((len - 7) / 255) + 1;
484 }
485 oc += 4;
486 }
487
488 /* update the hash at match boundary */
489 seq = BLOSCLZ_READU32(ip);
490 HASH_FUNCTION(hval, seq, HASH_LOG)
491 htab[hval] = (uint32_t) (ip++ - ibase);
492 seq >>= 8U;
493 HASH_FUNCTION(hval, seq, HASH_LOG)
494 htab[hval] = (uint32_t) (ip++ - ibase);
495 /* assuming literal copy */
496 oc++;
497
498 }
499
500 /* if we have copied something, adjust the copy length */
501 if (!copy)
502 oc--;
503
504 return (int)oc;
505 }
506
507
508 int blosclz_compress(const int clevel, const void* input, int length,
509 void* output, int maxout) {
342510 uint8_t* ibase = (uint8_t*)input;
343 uint8_t* ip_bound = ip + length - IP_BOUNDARY;
344 uint8_t* ip_limit = ip + length - 12;
511 uint8_t* ip = ibase;
512 uint8_t* ip_bound = ibase + length - 1;
513 uint8_t* ip_limit = ibase + length - 12;
345514 uint8_t* op = (uint8_t*)output;
346515 uint8_t* op_limit;
347 uint16_t htab[1U << (uint8_t)HASH_LOG];
348 int32_t hval;
516 uint32_t htab[1U << (uint8_t)HASH_LOG];
517 uint32_t hval;
518 uint32_t seq;
349519 uint8_t copy;
350 uint32_t nmax_copies = 0;
351 unsigned i;
352 uint8_t hashlog_[10] = {0, HASH_LOG - 4, HASH_LOG - 4, HASH_LOG - 3 , HASH_LOG - 2,
353 HASH_LOG - 1, HASH_LOG, HASH_LOG, HASH_LOG, HASH_LOG};
354 uint8_t hashlog = hashlog_[opt_level];
355 // The maximum amount of consecutive MAX_COPY copies before giving up
356 // 0 means something very close to RLE
357 uint8_t max_nmax_copies_[10] = {255U, 0U, 8U, 8U, 16U, 32U, 32U, 32U, 32U, 64U}; // 255 never used
358 uint8_t max_nmax_copies = max_nmax_copies_[opt_level];
359 double maxlength_[10] = {-1, .1, .2, .3, .4, .6, .9, .95, 1.0, 1.0};
360 int32_t maxlength = (int32_t)(length * maxlength_[opt_level]);
361
362 if (maxlength > (int32_t)maxout) {
363 maxlength = (int32_t)maxout;
364 }
365 op_limit = op + maxlength;
366
520
521 op_limit = op + maxout;
522
523 // Minimum lengths for encoding
524 unsigned minlen_[10] = {0, 12, 12, 11, 10, 9, 8, 7, 6, 5};
525
526 // Minimum compression ratios for initiate encoding
527 double cratio_[10] = {0, 2, 2, 2, 2, 1.8, 1.6, 1.4, 1.2, 1.1};
528
529 uint8_t hashlog_[10] = {0, HASH_LOG - 2, HASH_LOG - 1, HASH_LOG, HASH_LOG,
530 HASH_LOG, HASH_LOG, HASH_LOG, HASH_LOG, HASH_LOG};
531 uint8_t hashlog = hashlog_[clevel];
367532 // Initialize the hash table to distances of 0
368 for (i = 0; i < (1U << hashlog); i++) {
533 for (unsigned i = 0; i < (1U << hashlog); i++) {
369534 htab[i] = 0;
370535 }
371536
372 /* output buffer cannot be less than 66 bytes or we can get into trouble */
373 if (BLOSCLZ_UNEXPECT_CONDITIONAL(maxout < 66 || length < 4)) {
537 /* input and output buffer cannot be less than 16 and 66 bytes or we can get into trouble */
538 if (length < 16 || maxout < 66) {
374539 return 0;
375540 }
376541
542 /* When we go back in a match (shift), we obtain quite different compression properties.
543 * It looks like 4 is more useful in combination with bitshuffle and small typesizes
544 * (compress better and faster in e.g. `b2bench blosclz bitshuffle single 6 6291456 1 19`).
545 * Fallback to 4 because it provides more consistent results on small itemsizes.
546 *
547 * In this block we also check cratios for the beginning of the buffers and
548 * eventually discard those that are small (take too long to decompress).
549 * This process is called _entropy probing_.
550 */
551 int ipshift = 4;
552 int maxlen; // maximum length for entropy probing
553 int csize_3b;
554 int csize_4b;
555 double cratio = 0;
556 switch (clevel) {
557 case 1:
558 case 2:
559 case 3:
560 maxlen = length / 8;
561 csize_4b = get_csize(ibase, maxlen, false);
562 cratio = (double)maxlen / csize_4b;
563 break;
564 case 4:
565 case 5:
566 case 6:
567 case 7:
568 case 8:
569 maxlen = length / 8;
570 csize_4b = get_csize(ibase, maxlen, false);
571 cratio = (double)maxlen / csize_4b;
572 break;
573 case 9:
574 // case 9 is special. we need to asses the optimal shift
575 maxlen = length / 8;
576 csize_3b = get_csize(ibase, maxlen, true);
577 csize_4b = get_csize(ibase, maxlen, false);
578 ipshift = (csize_3b < csize_4b) ? 3 : 4;
579 cratio = (csize_3b < csize_4b) ? ((double)maxlen / csize_3b) : ((double)maxlen / csize_4b);
580 break;
581 default:
582 break;
583 }
584 // discard probes with small compression ratios (too expensive)
585 if (cratio < cratio_ [clevel]) {
586 goto out;
587 }
588
377589 /* we start with literal copy */
378 copy = 2;
590 copy = 4;
379591 *op++ = MAX_COPY - 1;
380592 *op++ = *ip++;
381593 *op++ = *ip++;
594 *op++ = *ip++;
595 *op++ = *ip++;
382596
383597 /* main loop */
384 while (BLOSCLZ_EXPECT_CONDITIONAL(ip < ip_limit)) {
598 while (BLOSCLZ_LIKELY(ip < ip_limit)) {
385599 const uint8_t* ref;
386 uint32_t distance;
387 uint32_t len = 3; /* minimum match length */
600 unsigned distance;
388601 uint8_t* anchor = ip; /* comparison starting-point */
389602
390 /* check for a run */
391 if (ip[0] == ip[-1] && BLOSCLZ_READU16(ip - 1) == BLOSCLZ_READU16(ip + 1)) {
392 distance = 1;
393 ref = anchor - 1 + 3;
394 goto match;
395 }
396
397603 /* find potential match */
398 HASH_FUNCTION(hval, ip, hashlog);
604 seq = BLOSCLZ_READU32(ip);
605 HASH_FUNCTION(hval, seq, hashlog)
399606 ref = ibase + htab[hval];
400607
401608 /* calculate distance to the match */
402 distance = (int32_t)(anchor - ref);
403
404 /* update hash table if necessary */
405 /* not exactly sure why masking the distance works best, but this is what the experiments say */
406 if (!shuffle || (distance & (MAX_COPY - 1)) == 0) {
407 htab[hval] = (uint16_t) (anchor - ibase);
408 }
609 distance = anchor - ref;
610
611 /* update hash table */
612 htab[hval] = (uint32_t) (anchor - ibase);
409613
410614 if (distance == 0 || (distance >= MAX_FARDISTANCE)) {
411615 LITERAL(ip, op, op_limit, anchor, copy)
616 continue;
412617 }
413618
414619 /* is this a match? check the first 4 bytes */
415 if (BLOSCLZ_READU32(ref) == BLOSCLZ_READU32(ip)) {
416 len = 4;
620 if (BLOSCLZ_UNLIKELY(BLOSCLZ_READU32(ref) == BLOSCLZ_READU32(ip))) {
417621 ref += 4;
418 }
419 /* check just the first 3 bytes */
420 else if (*ref++ != *ip++ || *ref++ != *ip++ || *ref++ != *ip) {
622 } else {
421623 /* no luck, copy as a literal */
422624 LITERAL(ip, op, op_limit, anchor, copy)
423 }
424
425 match:
625 continue;
626 }
426627
427628 /* last matched byte */
428 ip = anchor + len;
629 ip = anchor + 4;
429630
430631 /* distance is biased */
431632 distance--;
432633
433 if (!distance) {
434 /* zero distance means a run */
435 #if defined(__AVX2__)
436 ip = get_run_32(ip, ip_bound, ref);
437 #elif defined(__SSE2__)
438 ip = get_run_16(ip, ip_bound, ref);
439 #else
440 ip = get_run(ip, ip_bound, ref);
441 #endif
442 }
443 else {
444 #if defined(__AVX2__)
445 ip = get_match_32(ip, ip_bound + IP_BOUNDARY, ref);
446 #elif defined(__SSE2__)
447 ip = get_match_16(ip, ip_bound + IP_BOUNDARY, ref);
448 #else
449 ip = get_match(ip, ip_bound + IP_BOUNDARY, ref);
450 #endif
634 /* get runs or matches; zero distance means a run */
635 ip = get_run_or_match(ip, ip_bound, ref, !distance);
636
637 /* length is biased, '1' means a match of 3 bytes */
638 ip -= ipshift;
639
640 unsigned len = (int)(ip - anchor);
641 // If match is close, let's reduce the minimum length to encode it
642 unsigned minlen = (clevel == 9) ? ipshift : minlen_[clevel];
643
644 // Encoding short lengths is expensive during decompression
645 // Encode only for reasonable lengths (extensive experiments done)
646 if (len < minlen || (len <= 5 && distance >= MAX_DISTANCE)) {
647 LITERAL(ip, op, op_limit, anchor, copy)
648 continue;
451649 }
452650
453651 /* if we have copied something, adjust the copy count */
457655 else
458656 /* back, to overwrite the copy count */
459657 op--;
460
461658 /* reset literal counter */
462659 copy = 0;
463660
464 /* length is biased, '1' means a match of 3 bytes */
465 ip -= 3;
466 len = (int32_t)(ip - anchor);
467
468 /* check that we have space enough to encode the match for all the cases */
469 if (BLOSCLZ_UNEXPECT_CONDITIONAL(op + (len / 255) + 6 > op_limit)) goto out;
470
471661 /* encode the match */
472662 if (distance < MAX_DISTANCE) {
473 if (len < 7U) {
474 *op++ = (uint8_t)((len << 5U) + (distance >> 8U));
475 *op++ = (uint8_t)((distance & 255U));
476 }
477 else {
478 *op++ = (uint8_t)((7U << 5U) + (distance >> 8U));
479 for (len -= 7U; len >= 255U; len -= 255U)
480 *op++ = 255U;
481 *op++ = (uint8_t)len;
482 *op++ = (uint8_t)((distance & 255U));
483 }
484 }
485 else {
663 if (len < 7) {
664 DISTANCE_SHORT(op, op_limit, len, distance)
665 } else {
666 DISTANCE_LONG(op, op_limit, len, distance)
667 }
668 } else {
486669 /* far away, but not yet in the another galaxy... */
487 if (len < 7U) {
488 distance -= MAX_DISTANCE;
489 *op++ = (uint8_t)((len << 5U) + 31U);
490 *op++ = 255U;
491 *op++ = (uint8_t)(distance >> 8U);
492 *op++ = (uint8_t)(distance & 255U);
493 }
494 else {
495 distance -= MAX_DISTANCE;
496 *op++ = (7U << 5U) + 31U;
497 for (len -= 7U; len >= 255U; len -= 255U)
498 *op++ = 255U;
499 *op++ = (uint8_t)len;
500 *op++ = 255U;
501 *op++ = (uint8_t)(distance >> 8U);
502 *op++ = (uint8_t)(distance & 255U);
670 distance -= MAX_DISTANCE;
671 if (len < 7) {
672 DISTANCE_SHORT_FAR(op, op_limit, len, distance)
673 } else {
674 DISTANCE_LONG_FAR(op, op_limit, len, distance)
503675 }
504676 }
505677
506678 /* update the hash at match boundary */
507 if (ip < ip_limit) {
508 HASH_FUNCTION(hval, ip, hashlog);
509 htab[hval] = (uint16_t)(ip - ibase);
510 }
511 ip += 2;
679 seq = BLOSCLZ_READU32(ip);
680 HASH_FUNCTION(hval, seq, hashlog)
681 htab[hval] = (uint32_t) (ip++ - ibase);
682 seq >>= 8U;
683 HASH_FUNCTION(hval, seq, hashlog)
684 htab[hval] = (uint32_t) (ip++ - ibase);
512685 /* assuming literal copy */
686
687 if (BLOSCLZ_UNLIKELY(op + 1 > op_limit))
688 goto out;
513689 *op++ = MAX_COPY - 1;
514
515 // reset the number of max copies
516 nmax_copies = 0;
517690 }
518691
519692 /* left-over as literal copy */
520 ip_bound++;
521 while (ip <= ip_bound) {
522 if (BLOSCLZ_UNEXPECT_CONDITIONAL(op + 2 > op_limit)) goto out;
693 while (BLOSCLZ_UNLIKELY(ip <= ip_bound)) {
694 if (BLOSCLZ_UNLIKELY(op + 2 > op_limit)) goto out;
523695 *op++ = *ip++;
524696 copy++;
525 if (copy == MAX_COPY) {
697 if (BLOSCLZ_UNLIKELY(copy == MAX_COPY)) {
526698 copy = 0;
527699 *op++ = MAX_COPY - 1;
528700 }
541713
542714 out:
543715 return 0;
544
545716 }
546717
547718 // See https://habr.com/en/company/yandex/blog/457612/
563734
564735 static const ALIGNED_TYPE_(uint8_t, 16) masks[] =
565736 {
566 0, 1, 2, 1, 4, 1, 4, 2, 8, 7, 6, 5, 4, 3, 2, 1, // offset = 0, not used as mask, but for shift
567 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // offset = 1
568 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
569 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0,
570 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
571 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0,
572 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3,
573 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1,
574 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
575 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6,
576 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
577 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 2, 3, 4,
578 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3,
579 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2,
580 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 1,
581 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0,
582 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // offset = 16
737 0, 1, 2, 1, 4, 1, 4, 2, 8, 7, 6, 5, 4, 3, 2, 1, // offset = 0, not used as mask, but for shift
738 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // offset = 1
739 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
740 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0,
741 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
742 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0,
743 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3,
744 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1,
745 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
746 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6,
747 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
748 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 2, 3, 4,
749 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3,
750 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2,
751 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 1,
752 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0,
753 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // offset = 16
583754 };
584755
585756 _mm_storeu_si128((__m128i *)(op),
599770 }
600771 #endif
601772
602
603 /**
604 Define blosc_decompress and blosc_decompress_unsafe.
605 */
606 #define BLOSCLZ_SAFE
607 #include "blosclz_impl.inc"
608 #undef BLOSCLZ_SAFE
609 #define blosclz_decompress blosclz_decompress_unsafe
610 #include "blosclz_impl.inc"
611 #undef blosclz_decompress
773 // LZ4 wildCopy which can reach excellent copy bandwidth (even if insecure)
774 static inline void wild_copy(uint8_t *out, const uint8_t* from, uint8_t* end) {
775 uint8_t* d = out;
776 const uint8_t* s = from;
777 uint8_t* const e = end;
778
779 do { memcpy(d,s,8); d+=8; s+=8; } while (d<e);
780 }
781
782 int blosclz_decompress(const void* input, int length, void* output, int maxout) {
783 const uint8_t* ip = (const uint8_t*)input;
784 const uint8_t* ip_limit = ip + length;
785 uint8_t* op = (uint8_t*)output;
786 uint32_t ctrl;
787 uint8_t* op_limit = op + maxout;
788 if (BLOSCLZ_UNLIKELY(length == 0)) {
789 return 0;
790 }
791 ctrl = (*ip++) & 31U;
792
793 while (1) {
794 if (ctrl >= 32) {
795 // match
796 int32_t len = (ctrl >> 5U) - 1 ;
797 int32_t ofs = (ctrl & 31U) << 8U;
798 uint8_t code;
799 const uint8_t* ref = op - ofs;
800
801 if (len == 7 - 1) {
802 do {
803 if (BLOSCLZ_UNLIKELY(ip + 1 >= ip_limit)) {
804 return 0;
805 }
806 code = *ip++;
807 len += code;
808 } while (code == 255);
809 }
810 else {
811 if (BLOSCLZ_UNLIKELY(ip + 1 >= ip_limit)) {
812 return 0;
813 }
814 }
815 code = *ip++;
816 len += 3;
817 ref -= code;
818
819 /* match from 16-bit distance */
820 if (BLOSCLZ_UNLIKELY(code == 255)) {
821 if (ofs == (31U << 8U)) {
822 if (ip + 1 >= ip_limit) {
823 return 0;
824 }
825 ofs = (*ip++) << 8U;
826 ofs += *ip++;
827 ref = op - ofs - MAX_DISTANCE;
828 }
829 }
830
831 if (BLOSCLZ_UNLIKELY(op + len > op_limit)) {
832 return 0;
833 }
834
835 if (BLOSCLZ_UNLIKELY(ref - 1 < (uint8_t*)output)) {
836 return 0;
837 }
838
839 if (BLOSCLZ_UNLIKELY(ip >= ip_limit)) break;
840 ctrl = *ip++;
841
842 ref--;
843 if (ref == op - 1) {
844 /* optimized copy for a run */
845 memset(op, *ref, len);
846 op += len;
847 }
848 else if ((op - ref >= 8) && (op_limit - op >= len + 8)) {
849 // copy with an overlap not larger than 8
850 wild_copy(op, ref, op + len);
851 op += len;
852 }
853 else {
854 // general copy with any overlap
855 #ifdef __AVX2__
856 if (op - ref <= 16) {
857 // This is not faster on a combination of compilers (clang, gcc, icc) or machines, but
858 // it is not slower either. Let's activate here for experimentation.
859 op = copy_match_16(op, ref, len);
860 }
861 else {
862 #endif
863 op = copy_match(op, ref, (unsigned) len);
864 #ifdef __AVX2__
865 }
866 #endif
867 }
868 }
869 else {
870 // literal
871 ctrl++;
872 if (BLOSCLZ_UNLIKELY(op + ctrl > op_limit)) {
873 return 0;
874 }
875 if (BLOSCLZ_UNLIKELY(ip + ctrl > ip_limit)) {
876 return 0;
877 }
878
879 memcpy(op, ip, ctrl); op += ctrl; ip += ctrl;
880 // On GCC-6, fastcopy this is still faster than plain memcpy
881 // However, using recent CLANG/LLVM 9.0, there is almost no difference
882 // in performance.
883 // And starting on CLANG/LLVM 10 and GCC 9, memcpy is generally faster.
884 // op = fastcopy(op, ip, (unsigned) ctrl); ip += ctrl;
885
886 if (BLOSCLZ_UNLIKELY(ip >= ip_limit)) break;
887 ctrl = *ip++;
888 }
889 }
890
891 return (int)(op - (uint8_t*)output);
892 }
22
33 Author: Francesc Alted <francesc@blosc.org>
44
5 See LICENSES/BLOSC.txt for details about copyright and rights to use.
5 See LICENSE.txt for details about copyright and rights to use.
66 **********************************************************************/
77
88 /*********************************************************************
1818 #if defined (__cplusplus)
1919 extern "C" {
2020 #endif
21
2122
2223 /**
2324 Compress a block of data in the input buffer and returns the size of
3940 The input buffer and the output buffer can not overlap.
4041 */
4142
42 int blosclz_compress(const int opt_level, const void* input, int length,
43 void* output, int maxout, int shuffle);
43 int blosclz_compress(int opt_level, const void* input, int length,
44 void* output, int maxout);
4445
4546 /**
4647 Decompress a block of compressed data and returns the size of the
5657
5758 int blosclz_decompress(const void* input, int length, void* output, int maxout);
5859
59 /**
60 Same as above, except that it is not safe to run on invalid/untrusted input,
61 and may be slightly faster.
62 */
63 int blosclz_decompress_unsafe(const void* input, int length, void* output,
64 int maxout);
65
6660 #if defined (__cplusplus)
6761 }
6862 #endif
+0
-126
blosc/blosclz_impl.inc less more
0 /**
1 * Defines blosclz_decompress for a particular choice of BLOSCLZ_SAFE.
2 *
3 * This is included from blosclz.c once for each value of BLOSCLZ_SAFE.
4 */
5
6 int blosclz_decompress(const void* input, int length, void* output, int maxout) {
7 const uint8_t* ip = (const uint8_t*)input;
8 const uint8_t* ip_limit = ip + length;
9 uint8_t* op = (uint8_t*)output;
10 int32_t ctrl;
11 int32_t loop = 1;
12 #ifdef BLOSCLZ_SAFE
13 uint8_t* op_limit = op + maxout;
14 if (BLOSCLZ_UNEXPECT_CONDITIONAL(length == 0)) {
15 return 0;
16 }
17 #endif
18 ctrl = (*ip++) & 31;
19
20 do {
21 uint8_t* ref = op;
22 int32_t len = ctrl >> 5;
23 int32_t ofs = (ctrl & 31) << 8;
24
25 if (ctrl >= 32) {
26 uint8_t code;
27 len--;
28 ref -= ofs;
29 if (len == 7 - 1) {
30 do {
31 #ifdef BLOSCLZ_SAFE
32 if (BLOSCLZ_UNEXPECT_CONDITIONAL(ip + 1 >= ip_limit)) {
33 return 0;
34 }
35 #endif
36 code = *ip++;
37 len += code;
38 } while (code == 255);
39 } else {
40 #ifdef BLOSCLZ_SAFE
41 if (BLOSCLZ_UNEXPECT_CONDITIONAL(ip >= ip_limit)) {
42 return 0;
43 }
44 #endif
45 }
46 code = *ip++;
47 ref -= code;
48
49 /* match from 16-bit distance */
50 if (BLOSCLZ_UNEXPECT_CONDITIONAL(code == 255)) if (BLOSCLZ_EXPECT_CONDITIONAL(ofs == (31 << 8))) {
51 #ifdef BLOSCLZ_SAFE
52 if (BLOSCLZ_UNEXPECT_CONDITIONAL(ip + 1 >= ip_limit)) {
53 return 0;
54 }
55 #endif
56 ofs = (*ip++) << 8;
57 ofs += *ip++;
58 ref = op - ofs - MAX_DISTANCE;
59 }
60
61 #ifdef BLOSCLZ_SAFE
62 if (BLOSCLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit)) {
63 return 0;
64 }
65
66 if (BLOSCLZ_UNEXPECT_CONDITIONAL(ref - 1 < (uint8_t*)output)) {
67 return 0;
68 }
69 #endif
70
71 if (BLOSCLZ_EXPECT_CONDITIONAL(ip < ip_limit))
72 ctrl = *ip++;
73 else
74 loop = 0;
75
76 if (ref == op) {
77 /* optimized copy for a run */
78 uint8_t b = ref[-1];
79 memset(op, b, len + 3);
80 op += len + 3;
81 }
82 else {
83 /* copy from reference */
84 ref--;
85 len += 3;
86 #ifdef __AVX2__
87 if (op - ref <= 16) {
88 // This is not faster on a combination of compilers (clang, gcc, icc) or machines, but
89 // it is not slower either. Let's activate here for experimentation.
90 op = copy_match_16(op, ref, len);
91 }
92 else {
93 #endif
94 // We absolutely need a blosc_internal_copy_match here
95 op = blosc_internal_copy_match(op, ref, (unsigned) len);
96 #ifdef __AVX2__
97 }
98 #endif
99 }
100 }
101 else {
102 ctrl++;
103 #ifdef BLOSCLZ_SAFE
104 if (BLOSCLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit)) {
105 return 0;
106 }
107 if (BLOSCLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit)) {
108 return 0;
109 }
110 #endif
111
112 // memcpy(op, ip, ctrl); op += ctrl; ip += ctrl;
113 // On GCC-6, blosc_internal_fastcopy this is still faster than plain memcpy
114 // However, using recent CLANG/LLVM 9.0, there is almost no difference
115 // in performance.
116 op = blosc_internal_fastcopy(op, ip, (unsigned) ctrl); ip += ctrl;
117
118 loop = (int32_t)BLOSCLZ_EXPECT_CONDITIONAL(ip < ip_limit);
119 if (loop)
120 ctrl = *ip++;
121 }
122 } while (BLOSCLZ_EXPECT_CONDITIONAL(loop));
123
124 return (int)(op - (uint8_t*)output);
125 }
111111 __m256i chunk;
112112 chunk = _mm256_loadu_si256((__m256i*)from);
113113 _mm256_storeu_si256((__m256i*)out, chunk);
114 from += 32; out += 32;
114 out += 32;
115115 #elif defined(__SSE2__)
116116 __m128i chunk;
117117 chunk = _mm_loadu_si128((__m128i*)from);
138138 return out;
139139 }
140140
141 #if defined(__AVX2__)
142 static inline unsigned char *copy_32_bytes_aligned(unsigned char *out, const unsigned char *from) {
143 __m256i chunk;
144 chunk = _mm256_load_si256((__m256i*)from);
145 _mm256_storeu_si256((__m256i*)out, chunk);
146 return out + 32;
147 }
148 #endif // __AVX2__
141 // This is never used, so comment it out
142 //#if defined(__AVX2__)
143 //static inline unsigned char *copy_32_bytes_aligned(unsigned char *out, const unsigned char *from) {
144 // __m256i chunk;
145 // chunk = _mm256_load_si256((__m256i*)from);
146 // _mm256_storeu_si256((__m256i*)out, chunk);
147 // return out + 32;
148 //}
149 //#endif // __AVX2__
149150
150151 /* Copy LEN bytes (7 or fewer) from FROM into OUT. Return OUT + LEN. */
151152 static inline unsigned char *copy_bytes(unsigned char *out, const unsigned char *from, unsigned len) {
207208 case 7:
208209 out = copy_8_bytes(out, from);
209210 from += sz;
210 #ifdef AVOID_FALLTHROUGH_WARNING
211 #ifdef AVOID_FALLTHROUGH_WARNING
211212 __attribute__ ((fallthrough)); // Shut-up -Wimplicit-fallthrough warning in GCC
212 #endif
213 #endif
213214 case 6:
214215 out = copy_8_bytes(out, from);
215216 from += sz;
216 #ifdef AVOID_FALLTHROUGH_WARNING
217 #ifdef AVOID_FALLTHROUGH_WARNING
217218 __attribute__ ((fallthrough));
218 #endif
219 #endif
219220 case 5:
220221 out = copy_8_bytes(out, from);
221222 from += sz;
222 #ifdef AVOID_FALLTHROUGH_WARNING
223 #ifdef AVOID_FALLTHROUGH_WARNING
223224 __attribute__ ((fallthrough));
224 #endif
225 #endif
225226 case 4:
226227 out = copy_8_bytes(out, from);
227228 from += sz;
228 #ifdef AVOID_FALLTHROUGH_WARNING
229 #ifdef AVOID_FALLTHROUGH_WARNING
229230 __attribute__ ((fallthrough));
230 #endif
231 #endif
231232 case 3:
232233 out = copy_8_bytes(out, from);
233234 from += sz;
234 #ifdef AVOID_FALLTHROUGH_WARNING
235 #ifdef AVOID_FALLTHROUGH_WARNING
235236 __attribute__ ((fallthrough));
236 #endif
237 #endif
237238 case 2:
238239 out = copy_8_bytes(out, from);
239240 from += sz;
240 #ifdef AVOID_FALLTHROUGH_WARNING
241 #ifdef AVOID_FALLTHROUGH_WARNING
241242 __attribute__ ((fallthrough));
242 #endif
243 #endif
243244 case 1:
244245 out = copy_8_bytes(out, from);
245246 from += sz;
246 #ifdef AVOID_FALLTHROUGH_WARNING
247 #ifdef AVOID_FALLTHROUGH_WARNING
247248 __attribute__ ((fallthrough));
248 #endif
249 #endif
249250 default:
250251 break;
251252 }
491492
492493
493494 /* Byte by byte semantics: copy LEN bytes from FROM and write them to OUT. Return OUT + LEN. */
494 unsigned char *blosc_internal_fastcopy(unsigned char *out, const unsigned char *from, unsigned len) {
495 unsigned char *fastcopy(unsigned char *out, const unsigned char *from, unsigned len) {
495496 switch (len) {
496497 case 32:
497498 return copy_32_bytes(out, from);
524525
525526
526527 /* Copy a run */
527 unsigned char* blosc_internal_copy_match(unsigned char *out, const unsigned char *from, unsigned len) {
528 unsigned char* copy_match(unsigned char *out, const unsigned char *from, unsigned len) {
528529 #if defined(__AVX2__)
529530 unsigned sz = sizeof(__m256i);
530531 #elif defined(__SSE2__)
533534 unsigned sz = sizeof(uint64_t);
534535 #endif
535536
536 // If out and from are away more than the size of the copy, then a blosc_internal_fastcopy is safe
537 unsigned overlap_dist = (unsigned) (out - from);
538 if (overlap_dist > sz) {
539 return blosc_internal_fastcopy(out, from, len);
540 }
541
542537 #if ((defined(__GNUC__) && BLOSC_GCC_VERSION < 800) && !defined(__clang__) && !defined(__ICC) && !defined(__ICL))
543538 // GCC < 8 in fully optimization mode seems to have problems with the code further below so stop here
544539 for (; len > 0; len--) {
546541 }
547542 return out;
548543 #endif
544
545 // If out and from are away more than the size of the copy, then a fastcopy is safe
546 unsigned overlap_dist = (unsigned) (out - from);
547 if (overlap_dist > sz) {
548 return fastcopy(out, from, len);
549 }
549550
550551 // Otherwise we need to be more careful so as not to overwrite destination
551552 switch (overlap_dist) {
33 Author: Francesc Alted <francesc@blosc.org>
44 Creation date: 2018-01-03
55
6 See LICENSES/BLOSC.txt for details about copyright and rights to use.
6 See LICENSE.txt for details about copyright and rights to use.
77 **********************************************************************/
88
99 #ifndef BLOSC_FASTCOPY_H
1010 #define BLOSC_FASTCOPY_H
1111
1212 /* Same semantics than memcpy() */
13 unsigned char *blosc_internal_fastcopy(unsigned char *out, const unsigned char *from, unsigned len);
13 unsigned char *fastcopy(unsigned char *out, const unsigned char *from, unsigned len);
1414
15 /* Same as blosc_internal_fastcopy() but without overwriting origin or destination when they overlap */
16 unsigned char* blosc_internal_copy_match(unsigned char *out, const unsigned char *from, unsigned len);
15 /* Same as fastcopy() but without overwriting origin or destination when they overlap */
16 unsigned char* copy_match(unsigned char *out, const unsigned char *from, unsigned len);
1717
18 #endif /*BLOSC_FASTCOPY_H*/
18 #endif //BLOSC_FASTCOPY_H
77 **********************************************************************/
88
99 #include "shuffle.h"
10 #include "blosc-common.h"
1011 #include "shuffle-generic.h"
1112 #include "bitshuffle-generic.h"
1213 #include "blosc-comp-features.h"
171172 #define blosc_internal_cpuid(cpuInfo, function_id) blosc_internal_cpuidex(cpuInfo, function_id, 0)
172173
173174 #define _XCR_XFEATURE_ENABLED_MASK 0
175
176 #if !(defined(_IMMINTRIN_H_INCLUDED) && (BLOSC_GCC_VERSION >= 900))
174177
175178 /* Reads the content of an extended control register.
176179 https://software.intel.com/en-us/articles/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family
191194 return ((uint64_t)edx << 32) | eax;
192195 }
193196
194 #endif /* defined(_MSC_FULL_VER) */
197 #else
198
199 #define blosc_internal_xgetbv _xgetbv
200
201 #endif // !(defined(_IMMINTRIN_H_INCLUDED) && (BLOSC_GCC_VERSION >= 900))
202 #endif /* defined(_MSC_FULL_VER) */
195203
196204 #ifndef _XCR_XFEATURE_ENABLED_MASK
197205 #define _XCR_XFEATURE_ENABLED_MASK 0x0
403411 /* Initialize the shuffle implementation if necessary. */
404412 init_shuffle_implementation();
405413
406 if ((size % 8) == 0)
414 if ((size % 8) == 0) {
407415 /* The number of elems is a multiple of 8 which is supported by
408416 bitshuffle. */
409 return (int)(host_implementation.bitshuffle)((void*)_src, (void*)_dest,
410 blocksize / bytesoftype,
411 bytesoftype, (void*)_tmp);
412 else
413 memcpy((void*)_dest, (void*)_src, blocksize);
417 int ret = (int)(host_implementation.bitshuffle)((void *) _src, (void *) _dest,
418 blocksize / bytesoftype,
419 bytesoftype, (void *) _tmp);
420 /* Copy the leftovers */
421 size_t offset = size * bytesoftype;
422 memcpy((void *) (_dest + offset), (void *) (_src + offset), blocksize - offset);
423 return ret;
424 }
425 else {
426 memcpy((void *) _dest, (void *) _src, blocksize);
427 }
414428 return size;
415429 }
416430
424438 /* Initialize the shuffle implementation if necessary. */
425439 init_shuffle_implementation();
426440
427 if ((size % 8) == 0)
441 if ((size % 8) == 0) {
428442 /* The number of elems is a multiple of 8 which is supported by
429443 bitshuffle. */
430 return (int)(host_implementation.bitunshuffle)((void*)_src, (void*)_dest,
431 blocksize / bytesoftype,
432 bytesoftype, (void*)_tmp);
433 else
434 memcpy((void*)_dest, (void*)_src, blocksize);
444 int ret = (int) (host_implementation.bitunshuffle)((void *) _src, (void *) _dest,
445 blocksize / bytesoftype,
446 bytesoftype, (void *) _tmp);
447 /* Copy the leftovers */
448 size_t offset = size * bytesoftype;
449 memcpy((void *) (_dest + offset), (void *) (_src + offset), blocksize - offset);
450 return ret;
451 }
452 else {
453 memcpy((void *) _dest, (void *) _src, blocksize);
454 }
435455 return size;
436456 }
+0
-10
build.py less more
0 from conan.packager import ConanMultiPackager
1 import os
2
3 if __name__ == "__main__":
4 version = os.getenv("TRAVIS_TAG") or os.getenv("APPVEYOR_REPO_TAG_NAME") or "dev"
5 reference = "c-blosc/%s" % version
6 upload = os.getenv("CONAN_UPLOAD") if (version != "dev") else False
7 builder = ConanMultiPackager(reference=reference, upload=upload)
8 builder.add_common_builds(shared_option_name="c-blosc:shared")
9 builder.run()
0 # Code of Conduct
1
2 The Blosc community has adopted a Code of Conduct that we expect project participants to adhere to.
3 Please read the [full text](https://github.com/Blosc/community/blob/master/code_of_conduct.md)
4 so that you can understand what actions will and will not be tolerated.
1919 if (TEST_INCLUDE_COMPAT)
2020 file(GLOB DATAFILES *.cdata)
2121 foreach(datafile ${DATAFILES})
22 # Don't test data if compressor is deactivated
23 if((datafile MATCHES "lz4" AND DEACTIVATE_LZ4) OR
24 (datafile MATCHES "snappy" AND DEACTIVATE_SNAPPY) OR
25 (datafile MATCHES "zlib" AND DEACTIVATE_ZLIB) OR
26 (datafile MATCHES "zstd" AND DEACTIVATE_ZSTD))
27 continue()
28 endif()
2229 get_filename_component(fname ${datafile} NAME)
2330 add_test(test_compat_${fname} filegen decompress ${datafile})
2431 endforeach(datafile)
+0
-74
conanfile.py less more
0 import os
1 from conans import ConanFile, CMake, tools
2
3
4 class CbloscConan(ConanFile):
5 name = "c-blosc"
6 description = "An extremely fast, multi-threaded, meta-compressor library"
7 license = "BSD"
8 url = "https://github.com/Blosc/c-blosc"
9 settings = "os", "compiler", "build_type", "arch"
10 options = {"shared": [True, False]}
11 default_options = "shared=False"
12 generators = "cmake"
13 exports_sources = "*", "!test_package/*", "!appveyor*", "!.*.yml", "!bench/plot-speeds.py", "!build.py", "!.*"
14
15 @property
16 def run_tests(self):
17 return "CONAN_RUN_TESTS" in os.environ
18
19 def build(self):
20 os.mkdir("build")
21 tools.replace_in_file("CMakeLists.txt", "project(blosc)", '''project(blosc)
22 include(${CMAKE_BINARY_DIR}/../conanbuildinfo.cmake)
23 conan_basic_setup(NO_OUTPUT_DIRS)''')
24 cmake = CMake(self)
25 cmake.definitions["BUILD_TESTS"] = "ON" if self.run_tests else "OFF"
26 cmake.definitions["BUILD_BENCHMARKS"] = "ON" if self.run_tests else "OFF"
27 cmake.definitions["BUILD_SHARED"] = "ON" if (self.options.shared or self.run_tests) else "OFF"
28 cmake.definitions["BUILD_STATIC"] = "OFF" if self.options.shared else "ON"
29 cmake.configure(build_folder="build")
30 cmake.build()
31
32 if self.run_tests:
33 self.output.warn("Running tests!!")
34 self.launch_tests()
35
36 def launch_tests(self):
37 """Conan will remove rpaths from shared libs to be able to reuse the shared libs, we need
38 to tell the tests where to find the shared libs"""
39 test_args = "-VV" if tools.os_info.is_windows else ""
40 with tools.chdir("build"):
41 outdir = os.path.join(self.build_folder, "build", "blosc")
42 if tools.os_info.is_macos:
43 prefix = "DYLD_LIBRARY_PATH=%s" % outdir
44 elif tools.os_info.is_windows:
45 prefix = "PATH=%s;%%PATH%%" % outdir
46 elif tools.os_info.is_linux:
47 prefix = "LD_LIBRARY_PATH=%s" % outdir
48 else:
49 return
50 with tools.environment_append({'CTEST_OUTPUT_ON_FAILURE': '1'}):
51 self.run("%s ctest %s" % (prefix, test_args))
52
53 def package(self):
54 self.copy("blosc.h", dst="include", src="blosc")
55 self.copy("blosc-export.h", dst="include", src="blosc")
56 self.copy("*libblosc.a", dst="lib", keep_path=False)
57
58 if self.options.shared:
59 self.copy("*/blosc.lib", dst="lib", keep_path=False)
60 self.copy("*blosc.dll", dst="bin", keep_path=False)
61 self.copy("*blosc.*dylib*", dst="lib", keep_path=False, symlinks=True)
62 self.copy("*blosc.so*", dst="lib", keep_path=False, symlinks=True)
63 self.copy("*libblosc.dll.a", dst="lib", keep_path=False) # Mingw
64 else:
65 self.copy("*libblosc.lib", dst="lib", src="", keep_path=False)
66
67 def package_info(self):
68 if self.settings.compiler == "Visual Studio" and not self.options.shared:
69 self.cpp_info.libs = ["libblosc"]
70 else:
71 self.cpp_info.libs = ["blosc"]
72 if self.settings.os == "Linux":
73 self.cpp_info.libs.append("pthread")
+0
-8
test_package/CMakeLists.txt less more
0 project(PackageTest CXX)
1 cmake_minimum_required(VERSION 2.8.12)
2
3 include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
4 conan_basic_setup()
5
6 add_executable(example example.cpp)
7 target_link_libraries(example ${CONAN_LIBS})
+0
-24
test_package/conanfile.py less more
0 from conans import ConanFile, CMake, tools
1
2
3 class CbloscTestConan(ConanFile):
4 settings = "os", "compiler", "build_type", "arch"
5 generators = "cmake"
6
7 def build(self):
8 cmake = CMake(self)
9 cmake.configure()
10 cmake.build()
11
12 def imports(self):
13 self.copy("*.dll", dst="bin", src="bin" )
14 self.copy("*.dylib*", dst="bin", src="lib")
15 self.copy("*.so*", dst="bin", src="lib")
16
17 def test(self):
18 with tools.chdir("bin"):
19 if tools.os_info.is_windows:
20 self.run("example")
21 else:
22 prefix = "DYLD_LIBRARY_PATH=." if tools.os_info.is_macos else ""
23 self.run("%s ./example" % prefix)
+0
-59
test_package/example.cpp less more
0 #include <stdio.h>
1 #include <blosc.h>
2
3 #define SIZE 100*100*100
4
5 int main(){
6 static float data[SIZE];
7 static float data_out[SIZE];
8 static float data_dest[SIZE];
9 int isize = SIZE*sizeof(float), osize = SIZE*sizeof(float);
10 int dsize = SIZE*sizeof(float), csize;
11 int i;
12
13 for(i=0; i<SIZE; i++){
14 data[i] = i;
15 }
16
17 /* Register the filter with the library */
18 printf("Blosc version info: %s (%s)\n",
19 BLOSC_VERSION_STRING, BLOSC_VERSION_DATE);
20
21 /* Initialize the Blosc compressor */
22 blosc_init();
23
24 /* Compress with clevel=5 and shuffle active */
25 csize = blosc_compress(5, 1, sizeof(float), isize, data, data_out, osize);
26 if (csize == 0) {
27 printf("Buffer is uncompressible. Giving up.\n");
28 return 1;
29 }
30 else if (csize < 0) {
31 printf("Compression error. Error code: %d\n", csize);
32 return csize;
33 }
34
35 printf("Compression: %d -> %d (%.1fx)\n", isize, csize, (1.*isize) / csize);
36
37 /* Decompress */
38 dsize = blosc_decompress(data_out, data_dest, dsize);
39 if (dsize < 0) {
40 printf("Decompression error. Error code: %d\n", dsize);
41 return dsize;
42 }
43
44 printf("Decompression succesful!\n");
45
46 /* After using it, destroy the Blosc environment */
47 blosc_destroy();
48
49 for(i=0;i<SIZE;i++){
50 if(data[i] != data_dest[i]) {
51 printf("Decompressed data differs from original!\n");
52 return -1;
53 }
54 }
55
56 printf("Succesful roundtrip!\n");
57 return 0;
58 }
1919 endif()
2020 endif()
2121
22 # test_compressor will be enabled only when LZ4 support is in
23 if(target STREQUAL test_compressor AND DEACTIVATE_LZ4)
22 # Disable targets that use lz4 compressor when lz4 is deactivated
23 if((target STREQUAL test_compressor) OR (target STREQUAL test_bitshuffle_leftovers) AND DEACTIVATE_LZ4)
2424 message("Skipping ${target} on non-LZ4 builds")
2525 continue()
2626 endif()
0 # flags
1 link_directories(${PROJECT_BINARY_DIR}/blosc)
2
3 # look for fuzzing lib and link with it if found
4 if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
5 enable_language(CXX)
6
7 if(DEFINED ENV{LIB_FUZZING_ENGINE})
8 set(FUZZING_ENGINE $ENV{LIB_FUZZING_ENGINE})
9 set(FUZZING_ENGINE_FOUND TRUE)
10 else()
11 find_library(FUZZING_ENGINE "FuzzingEngine")
12 endif()
13 endif()
14
15 # If fuzzing lib not found then create standalone fuzz runner
16 if(NOT FUZZING_ENGINE_FOUND)
17 set(FUZZER_SRC standalone.c)
18 else()
19 set(FUZZER_SRC)
20 endif()
21
22 # sources
23 file(GLOB SOURCES fuzz_*.c)
24
25 # targets and tests
26 foreach(source ${SOURCES})
27 get_filename_component(target ${source} NAME_WE)
28
29 # Enable support for testing accelerated shuffles
30 if(COMPILER_SUPPORT_SSE2)
31 # Define a symbol so tests for SSE2 shuffle/unshuffle will be compiled in.
32 set_property(
33 SOURCE ${source}
34 APPEND PROPERTY COMPILE_DEFINITIONS SHUFFLE_SSE2_ENABLED)
35 endif(COMPILER_SUPPORT_SSE2)
36 # if(COMPILER_SUPPORT_AVX2)
37 # # Define a symbol so tests for AVX2 shuffle/unshuffle will be compiled in.
38 # set_property(
39 # SOURCE ${source}
40 # APPEND PROPERTY COMPILE_DEFINITIONS SHUFFLE_AVX2_ENABLED)
41 # endif(COMPILER_SUPPORT_AVX2)
42
43 add_executable(${target} ${source} ${FUZZER_SRC})
44
45 # OSS-Fuzz expect fuzzers to end with _fuzzer
46 string(REPLACE "fuzz_" "" output_name ${target})
47 set_target_properties(${target} PROPERTIES OUTPUT_NAME ${output_name}_fuzzer)
48
49 if(FUZZING_ENGINE_FOUND)
50 set_target_properties(${target} PROPERTIES LINKER_LANGUAGE CXX)
51 target_link_libraries(${target} ${FUZZING_ENGINE})
52 endif()
53
54 target_link_libraries(${target} blosc_static)
55 add_dependencies(${target} blosc_static)
56
57 # run standalone fuzzer against each file
58 file(GLOB COMPAT_FILES ${PROJECT_SOURCE_DIR}/compat/*.cdata)
59 add_test(NAME ${target} COMMAND ${target} ${COMPAT_FILES})
60
61 endforeach(source)
0 #include <stdint.h>
1 #include <stdlib.h>
2
3 #include "blosc.h"
4
5 #ifdef __cplusplus
6 extern "C" {
7 #endif
8
9 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
10 const char *compressors[] = { "blosclz", "lz4", "lz4hc", "snappy", "zlib", "zstd" };
11 int level = 9, filter = BLOSC_BITSHUFFLE, cindex = 0, i = 0;
12 size_t nbytes, cbytes, blocksize;
13 void *output, *input;
14
15 blosc_set_nthreads(1);
16
17 if (size > 0)
18 level = data[0] % (9 + 1);
19 if (size > 1)
20 filter = data[1] % (BLOSC_BITSHUFFLE + 1);
21 if (size > 2)
22 cindex = data[2];
23
24 /* Find next available compressor */
25 while (blosc_set_compressor(compressors[cindex % 6]) == -1 && i < 6) {
26 cindex++, i++;
27 }
28 if (i == 6) {
29 /* No compressors available */
30 return 0;
31 }
32
33 if (size > 3 && data[3] % 7 == 0)
34 blosc_set_blocksize(4096);
35
36 if (size > 4)
37 blosc_set_splitmode(data[4] % BLOSC_FORWARD_COMPAT_SPLIT + 1);
38
39 output = malloc(size + 1);
40 if (output == NULL)
41 return 0;
42
43 if (blosc_compress(level, filter, 1, size, data, output, size) == 0) {
44 /* Cannot compress src buffer into dest */
45 free(output);
46 return 0;
47 }
48
49 blosc_cbuffer_sizes(output, &nbytes, &cbytes, &blocksize);
50
51 input = malloc(cbytes);
52 if (input != NULL) {
53 blosc_decompress(output, input, cbytes);
54 free(input);
55 }
56
57 free(output);
58
59 return 0;
60 }
61
62 #ifdef __cplusplus
63 }
64 #endif
0 #include <stdint.h>
1 #include <stdlib.h>
2
3 #include "blosc.h"
4
5 #ifdef __cplusplus
6 extern "C" {
7 #endif
8
9 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
10 size_t nbytes, cbytes, blocksize;
11 void *output;
12
13 if (size < BLOSC_MIN_HEADER_LENGTH) {
14 return 0;
15 }
16
17 blosc_cbuffer_sizes(data, &nbytes, &cbytes, &blocksize);
18 if (cbytes != size) {
19 return 0;
20 }
21 if (nbytes == 0) {
22 return 0;
23 }
24
25 if (blosc_cbuffer_validate(data, size, &nbytes) != 0) {
26 /* Unexpected nbytes specified in blosc header */
27 return 0;
28 }
29
30 output = malloc(cbytes);
31 if (output != NULL) {
32 blosc_decompress(data, output, cbytes);
33 free(output);
34 }
35 return 0;
36 }
37
38 #ifdef __cplusplus
39 }
40 #endif
0 #include <assert.h>
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
5
6 int main(int argc, char **argv) {
7 int i;
8 fprintf(stderr, "Running %d inputs\n", argc - 1);
9
10 for (i = 1; i < argc; i++) {
11 size_t len, err, n_read = 0;
12 unsigned char *buf;
13 FILE *f = NULL;
14
15 f = fopen(argv[i], "rb+");
16 if (f == NULL) {
17 /* Failed to open this file: it may be a directory. */
18 fprintf(stderr, "Skipping: %s\n", argv[i]);
19 continue;
20 }
21 fprintf(stderr, "Running: %s %s\n", argv[0], argv[i]);
22
23 fseek(f, 0, SEEK_END);
24 len = ftell(f);
25 fseek(f, 0, SEEK_SET);
26
27 buf = (unsigned char *)malloc(len);
28 if (buf != NULL) {
29 n_read = fread(buf, 1, len, f);
30 assert(n_read == len);
31 LLVMFuzzerTestOneInput(buf, len);
32 free(buf);
33 }
34
35 err = fclose(f);
36 assert(err == 0);
37 (void)err;
38
39 fprintf(stderr, "Done: %s: (%d bytes)\n", argv[i], (int)n_read);
40 }
41
42 return 0;
43 }
0 /*********************************************************************
1 Blosc - Blocked Shuffling and Compression Library
2
3 Unit test for the bitshuffle with blocks that are not aligned.
4 See https://github.com/Blosc/python-blosc/issues/220
5 Probably related: https://github.com/Blosc/c-blosc/issues/240
6
7 Creation date: 2020-02-18
8 Author: Francesc Alted <francesc@blosc.org>
9
10 See LICENSES/BLOSC.txt for details about copyright and rights to use.
11 **********************************************************************/
12
13 #include "test_common.h"
14
15
16 static int test_roundtrip_bitshuffle8(int size, void *data, void *data_out, void *data_dest) {
17 /* Compress with bitshuffle active */
18 int isize = size;
19 int osize = size + BLOSC_MIN_HEADER_LENGTH;
20 int csize = blosc_compress(9, BLOSC_BITSHUFFLE, 8, isize, data, data_out, osize);
21 int dsize;
22 int exit_code;
23 FILE *fout = fopen("test-bitshuffle8-nomemcpy.cdata", "w");
24
25 if (csize == 0) {
26 printf("Buffer is uncompressible. Giving up.\n");
27 return 1;
28 }
29 else if (csize < 0) {
30 printf("Compression error. Error code: %d\n", csize);
31 return csize;
32 }
33 printf("Compression: %d -> %d (%.1fx)\n", isize, csize, (1.*isize) / csize);
34
35 fwrite(data_out, csize, 1, fout);
36 fclose(fout);
37
38 /* Decompress */
39 dsize = blosc_decompress(data_out, data_dest, isize);
40 if (dsize < 0) {
41 printf("Decompression error. Error code: %d\n", dsize);
42 return dsize;
43 }
44
45 printf("Decompression succesful!\n");
46
47 exit_code = memcmp(data, data_dest, size) ? EXIT_FAILURE : EXIT_SUCCESS;
48
49 if (exit_code == EXIT_SUCCESS)
50 printf("Succesful roundtrip!\n");
51 else
52 printf("Decompressed data differs from original!\n");
53
54 return exit_code;
55 }
56
57 static int test_roundtrip_bitshuffle4(int size, void *data, void *data_out, void *data_dest) {
58 /* Compress with bitshuffle active */
59 int isize = size;
60 int osize = size + BLOSC_MIN_HEADER_LENGTH;
61 int csize = blosc_compress(9, BLOSC_BITSHUFFLE, 4, isize, data, data_out, osize);
62 int dsize;
63 int exit_code;
64 FILE *fout = fopen("test-bitshuffle4-memcpy.cdata", "w");
65
66 if (csize == 0) {
67 printf("Buffer is uncompressible. Giving up.\n");
68 return 1;
69 }
70 else if (csize < 0) {
71 printf("Compression error. Error code: %d\n", csize);
72 return csize;
73 }
74 printf("Compression: %d -> %d (%.1fx)\n", isize, csize, (1.*isize) / csize);
75
76 fwrite(data_out, csize, 1, fout);
77 fclose(fout);
78
79 /* Decompress */
80 dsize = blosc_decompress(data_out, data_dest, isize);
81 if (dsize < 0) {
82 printf("Decompression error. Error code: %d\n", dsize);
83 return dsize;
84 }
85
86 printf("Decompression succesful!\n");
87
88 exit_code = memcmp(data, data_dest, size) ? EXIT_FAILURE : EXIT_SUCCESS;
89 if (exit_code == EXIT_SUCCESS)
90 printf("Succesful roundtrip!\n");
91 else
92 printf("Decompressed data differs from original!\n");
93
94 return exit_code;
95 }
96
97 int main() {
98 /* `size` below is chosen so that it is not divisible by 8
99 * (not supported by bitshuffle) and in addition, it is not
100 * divisible by 8 (typesize) again.
101 */
102 int size = 641091;
103 int32_t *data = malloc(size);
104 int32_t *data_out = malloc(size + BLOSC_MIN_HEADER_LENGTH);
105 int32_t *data_dest = malloc(size);
106 int result;
107 int i;
108
109 /* Initialize data */
110 for (i = 0; i < size / sizeof(int32_t); i++) {
111 ((uint32_t*)data)[i] = i;
112 }
113 /* leftovers */
114 for (i = size / sizeof(int32_t) * sizeof(int32_t); i < size; i++) {
115 ((uint8_t*)data)[i] = i;
116 }
117
118 blosc_init();
119 blosc_set_nthreads(1);
120 blosc_set_compressor("lz4");
121 printf("Blosc version info: %s (%s)\n", BLOSC_VERSION_STRING, BLOSC_VERSION_DATE);
122 result = test_roundtrip_bitshuffle4(size, data, data_out, data_dest);
123 if (result != EXIT_SUCCESS) {
124 goto fail;
125 }
126 result = test_roundtrip_bitshuffle8(size, data, data_out, data_dest);
127 if (result != EXIT_SUCCESS) {
128 goto fail;
129 }
130
131 free(data);
132 free(data_out);
133 free(data_dest);
134
135 blosc_destroy();
136
137 fail:
138 return result;
139 }
150150 int cbytes2;
151151
152152 /* Get a compressed buffer */
153 blosc_set_compressor("blosclz"); /* avoid lz4 here for now (see #BLOSC_MAX_OVERHEAD8) */
153 blosc_set_compressor("lz4"); /* avoid lz4 here for now (see #BLOSC_MAX_OVERHEAD8) */
154154 cbytes = blosc_compress(clevel, doshuffle, typesize, size, src,
155155 dest, size + BLOSC_MAX_OVERHEAD);
156156 mu_assert("ERROR: cbytes is not 0", cbytes < size);
159159 setenv("BLOSC_SHUFFLE", "BITSHUFFLE", 0);
160160 cbytes2 = blosc_compress(clevel, doshuffle, typesize, size, src,
161161 dest, size + BLOSC_MAX_OVERHEAD);
162 /* For some reason, shuffle is unreasonably efficient here (much more than bitshuffle) */
162163 mu_assert("ERROR: BLOSC_SHUFFLE=BITSHUFFLE does not work correctly",
163 cbytes2 < cbytes * 1.5);
164 cbytes2 < cbytes * 20);
164165
165166 /* Reset env var */
166167 unsetenv("BLOSC_SHUFFLE");
2121 size_t size = 1000; /* must be divisible by 4 */
2222
2323
24 /* Check input size > BLOSC_MAX_BUFFERSIZE */
25 static const char *test_input_too_large(void) {
26
27 /* Get a compressed buffer */
28 cbytes = blosc_compress(clevel, doshuffle, typesize, BLOSC_MAX_BUFFERSIZE + 1, src,
29 dest, size + BLOSC_MAX_OVERHEAD - 1);
30 mu_assert("ERROR: cbytes is not 0", cbytes == 0);
31
32 return 0;
33 }
34
35
2436 /* Check maxout with maxout < size */
2537 static const char *test_maxout_less(void) {
2638
2739 /* Get a compressed buffer */
28 cbytes = blosc_compress(clevel, doshuffle, typesize, size, src, dest, size + BLOSC_MAX_OVERHEAD - 1);
40 cbytes = blosc_compress(clevel, doshuffle, typesize, size, src, dest,
41 size + BLOSC_MAX_OVERHEAD - 1);
2942 mu_assert("ERROR: cbytes is not 0", cbytes == 0);
3043
3144 return 0;
3649 static const char *test_maxout_less_memcpy(void) {
3750
3851 /* Get a compressed buffer */
39 cbytes = blosc_compress(0, doshuffle, typesize, size, src, dest, size + BLOSC_MAX_OVERHEAD - 1);
52 cbytes = blosc_compress(0, doshuffle, typesize, size, src, dest,
53 size + BLOSC_MAX_OVERHEAD - 1);
4054 mu_assert("ERROR: cbytes is not 0", cbytes == 0);
4155
4256 return 0;
4761 static const char *test_maxout_equal(void) {
4862
4963 /* Get a compressed buffer */
50 cbytes = blosc_compress(clevel, doshuffle, typesize, size, src, dest, size + BLOSC_MAX_OVERHEAD);
64 cbytes = blosc_compress(clevel, doshuffle, typesize, size, src, dest,
65 size + BLOSC_MAX_OVERHEAD);
5166 mu_assert("ERROR: cbytes is not correct", cbytes == size + BLOSC_MAX_OVERHEAD);
5267
5368 /* Decompress the buffer */
6277 static const char *test_maxout_equal_memcpy(void) {
6378
6479 /* Get a compressed buffer */
65 cbytes = blosc_compress(0, doshuffle, typesize, size, src, dest, size + BLOSC_MAX_OVERHEAD);
80 cbytes = blosc_compress(0, doshuffle, typesize, size, src, dest,
81 size + BLOSC_MAX_OVERHEAD);
6682 mu_assert("ERROR: cbytes is not correct", cbytes == size + BLOSC_MAX_OVERHEAD);
6783
6884 /* Decompress the buffer */
7692 /* Check maxout with maxout > size */
7793 static const char *test_maxout_great(void) {
7894 /* Get a compressed buffer */
79 cbytes = blosc_compress(clevel, doshuffle, typesize, size, src, dest, size + BLOSC_MAX_OVERHEAD + 1);
95 cbytes = blosc_compress(clevel, doshuffle, typesize, size, src, dest,
96 size + BLOSC_MAX_OVERHEAD + 1);
8097 mu_assert("ERROR: cbytes is not correct", cbytes == size + BLOSC_MAX_OVERHEAD);
8198
8299 /* Decompress the buffer */
90107 /* Check maxout with maxout > size (memcpy version) */
91108 static const char *test_maxout_great_memcpy(void) {
92109 /* Get a compressed buffer */
93 cbytes = blosc_compress(0, doshuffle, typesize, size, src, dest, size + BLOSC_MAX_OVERHEAD + 1);
110 cbytes = blosc_compress(0, doshuffle, typesize, size, src, dest,
111 size + BLOSC_MAX_OVERHEAD + 1);
94112 mu_assert("ERROR: cbytes is not correct", cbytes == size + BLOSC_MAX_OVERHEAD);
95113
96114 /* Decompress the buffer */
103121 /* Check maxout with maxout < BLOSC_MAX_OVERHEAD */
104122 static const char *test_max_overhead(void) {
105123 blosc_init();
106 cbytes = blosc_compress(0, doshuffle, typesize, size, src, dest, BLOSC_MAX_OVERHEAD - 1);
107 mu_assert("ERROR: cbytes is not correct", cbytes < 0);
124 cbytes = blosc_compress(0, doshuffle, typesize, size, src, dest,
125 BLOSC_MAX_OVERHEAD - 1);
126 mu_assert("ERROR: cbytes is not correct", cbytes == 0);
108127 blosc_destroy();
109128
110129 blosc_init();
111 cbytes = blosc_compress(0, doshuffle, typesize, size, src, dest, BLOSC_MAX_OVERHEAD - 2);
112 mu_assert("ERROR: cbytes is not correct", cbytes < 0);
130 cbytes = blosc_compress(0, doshuffle, typesize, size, src, dest,
131 BLOSC_MAX_OVERHEAD - 2);
132 mu_assert("ERROR: cbytes is not correct", cbytes == 0);
113133 blosc_destroy();
114134
115135 blosc_init();
116136 cbytes = blosc_compress(0, doshuffle, typesize, size, src, dest, 0);
117 mu_assert("ERROR: cbytes is not correct", cbytes < 0);
137 mu_assert("ERROR: cbytes is not correct", cbytes == 0);
118138 blosc_destroy();
119139
120140 return 0;
122142
123143
124144 static const char *all_tests(void) {
145 mu_run_test(test_input_too_large);
125146 mu_run_test(test_maxout_less);
126147 mu_run_test(test_maxout_less_memcpy);
127148 mu_run_test(test_maxout_equal);
174195 blosc_destroy();
175196
176197 return result != 0;
177 }
198 }