├── .gitignore ├── fpm.toml ├── LICENCE ├── Makefile ├── README.md ├── test └── test_zstd.f90 ├── COVERAGE.md └── src └── zstd.F90 /.gitignore: -------------------------------------------------------------------------------- 1 | env/ 2 | build/ 3 | dist/ 4 | *.a 5 | *.mod 6 | *.o 7 | *.so 8 | *.swp 9 | -------------------------------------------------------------------------------- /fpm.toml: -------------------------------------------------------------------------------- 1 | name = "fortran-zstd" 2 | version = "0.1.0" 3 | license = "ISC" 4 | author = "Philipp Engel" 5 | maintainer = "@interkosmos" 6 | copyright = "Copyright (c) 2024, Philipp Engel" 7 | description = "Fortran 2018 ISO C binding interfaces to Zstandard (zstd)" 8 | keywords = [ "compression", "zstandard", "zstd" ] 9 | 10 | [build] 11 | link = "zstd" 12 | 13 | [library] 14 | source-dir = "src" 15 | 16 | [install] 17 | library = true 18 | 19 | [[test]] 20 | name = "test_zstd" 21 | source-dir = "test" 22 | main = "test_zstd.f90" 23 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024, Philipp Engel 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose 4 | with or without fee is hereby granted, provided that the above copyright notice 5 | and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 8 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 9 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 10 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 11 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 12 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 13 | THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .POSIX: 2 | .SUFFIXES: 3 | 4 | FC = gfortran 5 | AR = ar 6 | MAKE = make 7 | PREFIX = /usr/local 8 | 9 | DEBUG = -g -O0 -Wall -fmax-errors=1 -std=f2018 10 | RELEASE = -O2 11 | 12 | FFLAGS = $(RELEASE) 13 | LDFLAGS = -I$(PREFIX)/include -L$(PREFIX)/lib 14 | LDLIBS = -lzstd 15 | ARFLAGS = rcs 16 | INCDIR = $(PREFIX)/include/libfortran-zstd 17 | LIBDIR = $(PREFIX)/lib 18 | SRC = src/zstd.F90 19 | MODULE = zstd.mod 20 | TARGET = ./libfortran-zstd.a 21 | SHARED = ./libfortran-zstd.so 22 | 23 | .PHONY: all clean debug install shared test test_shared 24 | 25 | all: $(TARGET) 26 | 27 | shared: $(SHARED) 28 | 29 | debug: 30 | $(MAKE) FFLAGS="$(DEBUG)" 31 | $(MAKE) test FFLAGS="$(DEBUG)" 32 | 33 | $(TARGET): $(SRC) 34 | $(FC) $(FFLAGS) -c $(SRC) 35 | $(AR) $(ARFLAGS) $(TARGET) zstd.o 36 | 37 | $(SHARED): $(SRC) 38 | $(FC) $(FFLAGS) -fPIC -shared -o $(SHARED) $(SRC) $(LDLIBS) 39 | 40 | test: $(TARGET) test/test_zstd.f90 41 | $(FC) $(FFLAGS) $(LDFLAGS) -o test_zstd test/test_zstd.f90 $(TARGET) $(LDLIBS) 42 | 43 | test_shared: $(SHARED) test/test_zstd.f90 44 | $(FC) $(FFLAGS) $(LDFLAGS) -o test_zstd_shared test/test_zstd.f90 $(SHARED) $(LDLIBS) 45 | 46 | install: $(TARGET) 47 | @echo "--- Installing library to $(LIBDIR)/ ..." 48 | install -d $(LIBDIR) 49 | install -m 644 $(TARGET) $(LIBDIR)/ 50 | if [ -e $(SHARED) ]; then install -m 644 $(SHARED) $(LIBDIR)/; fi 51 | @echo "--- Installing module to $(INCDIR)/ ..." 52 | install -d $(INCDIR) 53 | install -m 644 $(MODULE) $(INCDIR)/ 54 | 55 | clean: 56 | if [ `ls -1 *.mod 2>/dev/null | wc -l` -gt 0 ]; then rm *.mod; fi 57 | if [ `ls -1 *.o 2>/dev/null | wc -l` -gt 0 ]; then rm *.o; fi 58 | if [ -e $(TARGET) ]; then rm $(TARGET); fi 59 | if [ -e $(SHARED) ]; then rm $(SHARED); fi 60 | if [ -e test_zstd ]; then rm test_zstd; fi 61 | if [ -e test_zstd_shared ]; then rm test_zstd_shared; fi 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fortran-zstd 2 | 3 | A collection of Fortran 2018 interface bindings to selected 4 | [Zstandard](http://www.zstd.net/) functions (zstd ≥ 1.5.5). In comparison to the 5 | original C API, the Fortran interfaces, types, and arguments have been converted 6 | to snake case. See [COVERAGE](COVERAGE.md) for an overview of bound procedures. 7 | 8 | ## Build Instructions 9 | 10 | The zstd library has to be installed with development headers. On FreeBSD, run: 11 | 12 | ``` 13 | # pkg install archivers/zstd 14 | ``` 15 | 16 | On Linux, instead: 17 | 18 | ``` 19 | # apt-get install libzstd1 libzstd-dev 20 | ``` 21 | 22 | Or, to build the zstd library from source, and to install to `/usr/local`, run: 23 | 24 | ``` 25 | $ cd /tmp/ 26 | $ git clone --depth 1 https://github.com/facebook/zstd 27 | $ cd zstd/build/cmake/ 28 | $ mkdir build && cd build/ 29 | $ cmake .. 30 | $ cmake --build . --config Release 31 | $ sudo cmake --install . --prefix /usr/local 32 | ``` 33 | 34 | Build and install the Fortran library using the provided Makefile: 35 | 36 | ``` 37 | $ make 38 | $ make install PREFIX=/opt 39 | ``` 40 | 41 | Link your programs against `/opt/lib/libfortran-zstd.a -lzstd`. Optionally, 42 | overwrite the default compiler and the compiler flags: 43 | 44 | ``` 45 | $ make FC=ifx FFLAGS="-O3" 46 | ``` 47 | 48 | Or, use the [Fortran Package Manager](https://github.com/fortran-lang/fpm): 49 | 50 | ``` 51 | $ fpm build --profile release 52 | ``` 53 | 54 | Build and run the test program: 55 | 56 | ``` 57 | $ make test 58 | $ ./test_zstd 59 | ``` 60 | 61 | ## Example 62 | 63 | The following basic example compresses and uncompresses an input string. 64 | 65 | ```fortran 66 | ! example.f90 67 | program main 68 | use :: zstd 69 | implicit none (type, external) 70 | 71 | character(len=:), allocatable :: dst1, dst2, src 72 | integer(kind=c_size_t) :: dst_len, src_len, stat 73 | 74 | src = repeat('Hello, there! ', 32) 75 | 76 | src_len = len(src, kind=c_size_t) 77 | dst_len = zstd_compress_bound(src_len) 78 | 79 | allocate (character(len=dst_len) :: dst1) 80 | allocate (character(len=src_len) :: dst2) 81 | 82 | stat = zstd_compress(dst1, dst_len, src, src_len, zstd_default_c_level()) 83 | dst_len = stat 84 | 85 | if (zstd_is_error(stat)) then 86 | print '("zstd_compress: ", a)', zstd_get_error_name(stat) 87 | error stop 88 | end if 89 | 90 | stat = zstd_decompress(dst2, src_len, dst1, dst_len) 91 | 92 | if (zstd_is_error(stat)) then 93 | print '("zstd_decompress: ", a)', zstd_get_error_name(stat) 94 | error stop 95 | end if 96 | end program main 97 | ``` 98 | 99 | If the library has been installed to `/opt`, then compile, link, and run the 100 | example program with: 101 | 102 | ``` 103 | $ gfortran -I/opt/include/libfortran-zstd -o example example.f90 \ 104 | /opt/lib/libfortran-zstd.a -lzstd 105 | $ ./example 106 | ``` 107 | 108 | ## Fortran Package Manager 109 | 110 | You can add *fortran-zstd* as an FPM dependency: 111 | 112 | ```toml 113 | [dependencies] 114 | fortran-zstd = { git = "https://github.com/interkosmos/fortran-zstd.git" } 115 | ``` 116 | 117 | ## References 118 | 119 | * [Zstandard manual](http://facebook.github.io/zstd/zstd_manual.html) 120 | * [Zstandard repository](https://github.com/facebook/zstd) 121 | * [Zstandard website](http://www.zstd.net/) 122 | 123 | ## Licence 124 | 125 | ISC 126 | -------------------------------------------------------------------------------- /test/test_zstd.f90: -------------------------------------------------------------------------------- 1 | ! test_zstd.f90 2 | ! 3 | ! Author: Philipp Engel 4 | ! Licence: ISC 5 | program main 6 | use :: zstd 7 | implicit none (type, external) 8 | 9 | integer, parameter :: NTESTS = 3 10 | 11 | integer :: i 12 | logical :: tests(NTESTS) 13 | 14 | print '("zstd version number: ", i0)', zstd_version_number() 15 | print '("zstd version string: ", a)', zstd_version_string() 16 | 17 | tests(1) = test_simple() 18 | tests(2) = test_simple_multi() 19 | tests(3) = test_stream() 20 | 21 | do i = 1, NTESTS 22 | if (.not. tests(i)) error stop 23 | end do 24 | contains 25 | integer(kind=c_size_t) function test_read(chunk, pos, to_read, src) result(nbytes) 26 | !! Reads chunk from source `src` and returns chunk length. 27 | character(len=*), intent(inout) :: chunk !! Output chunk. 28 | integer(kind=c_size_t), intent(inout) :: pos !! Current cursor position. 29 | integer(kind=c_size_t), intent(in) :: to_read !! Max. bytes to read. 30 | character(len=*), intent(inout) :: src !! Source to read from. 31 | 32 | integer :: pos2 33 | 34 | nbytes = 0 35 | if (to_read == 0) return 36 | 37 | pos = pos + 1 38 | if (pos > len(src)) return 39 | 40 | pos2 = min(pos + to_read, len(src, kind=c_size_t)) 41 | chunk = src(pos:pos2) 42 | nbytes = abs(pos2 - pos) + 1 43 | pos = pos2 44 | end function test_read 45 | 46 | logical function test_simple() result(success) 47 | !! Simple API. 48 | character(len=:), allocatable :: dst1, dst2, src 49 | integer :: level 50 | integer(kind=c_size_t) :: dst_len, src_len 51 | integer(kind=c_size_t) :: stat 52 | 53 | success = .false. 54 | 55 | print '(">>> test_simple")' 56 | 57 | src = repeat('Now is the time for all good men to come to the aid of the party. ', 128) 58 | 59 | src_len = len(src, kind=c_size_t) 60 | dst_len = zstd_compress_bound(src_len) 61 | 62 | allocate (character(len=dst_len) :: dst1) 63 | allocate (character(len=src_len) :: dst2) 64 | 65 | level = zstd_default_c_level() 66 | stat = zstd_compress(dst1, dst_len, src, src_len, level) 67 | 68 | if (zstd_is_error(stat)) then 69 | print '("zstd_compress: ", a)', zstd_get_error_name(stat) 70 | return 71 | end if 72 | 73 | dst_len = stat 74 | 75 | print '("src length: ", i0)', src_len 76 | print '("dst length: ", i0)', dst_len 77 | 78 | stat = zstd_decompress(dst2, src_len, dst1, dst_len) 79 | 80 | if (zstd_is_error(stat)) then 81 | print '("zstd_decompress: ", a)', zstd_get_error_name(stat) 82 | return 83 | end if 84 | 85 | if (dst2 /= src) then 86 | print '("data mismatch")' 87 | return 88 | end if 89 | 90 | success = .true. 91 | end function test_simple 92 | 93 | logical function test_simple_multi() result(success) 94 | !! Multiple simple API. 95 | character(len=:), allocatable :: dst1, dst2, src 96 | integer :: level 97 | integer(kind=c_size_t) :: dst_len, src_len 98 | integer(kind=c_size_t) :: stat, stat2 99 | type(c_ptr) :: c_ctx, d_ctx 100 | 101 | success = .false. 102 | 103 | print '(">>> test_simple_multi")' 104 | 105 | src = repeat('Now is the time for all good men to come to the aid of the party. ', 128) 106 | 107 | src_len = len(src, kind=c_size_t) 108 | dst_len = zstd_compress_bound(src_len) 109 | 110 | allocate (character(len=dst_len) :: dst1) 111 | allocate (character(len=src_len) :: dst2) 112 | 113 | c_ctx = zstd_create_c_ctx() 114 | level = zstd_default_c_level() 115 | stat = zstd_compress_c_ctx(c_ctx, dst1, dst_len, src, src_len, level) 116 | stat2 = zstd_free_c_ctx(c_ctx) 117 | 118 | if (zstd_is_error(stat)) then 119 | print '("zstd_compress: ", a)', zstd_get_error_name(stat) 120 | return 121 | end if 122 | 123 | dst_len = stat 124 | 125 | print '("src length: ", i0)', src_len 126 | print '("dst length: ", i0)', dst_len 127 | 128 | d_ctx = zstd_create_d_ctx() 129 | stat = zstd_decompress_d_ctx(d_ctx, dst2, src_len, dst1, dst_len) 130 | stat2 = zstd_free_d_ctx(d_ctx) 131 | 132 | if (zstd_is_error(stat)) then 133 | print '("zstd_decompress: ", a)', zstd_get_error_name(stat) 134 | return 135 | end if 136 | 137 | if (dst2 /= src) then 138 | print '("data mismatch")' 139 | return 140 | end if 141 | 142 | success = .true. 143 | end function test_simple_multi 144 | 145 | logical function test_stream() result(success) 146 | !! Streaming API. 147 | character(len=:), allocatable :: dst, src1, src2 148 | integer(kind=c_size_t) :: stat 149 | 150 | success = .true. 151 | 152 | print '(">>> test_stream")' 153 | 154 | src1 = repeat('Now is the time for all good men to come to the aid of the party. ', 128) 155 | src2 = '' 156 | dst = '' 157 | 158 | ! Compression: src1 -> dst. 159 | c_block: block 160 | character(len=:), allocatable, target :: buf_in, buf_out 161 | 162 | integer :: level, mode 163 | integer(kind=c_size_t) :: buf_in_sz, buf_out_sz 164 | integer(kind=c_size_t) :: nbytes, pos, remaining, to_read 165 | logical :: finished, last_chunk 166 | type(c_ptr) :: c_ctx 167 | type(zstd_in_buffer_type) :: input 168 | type(zstd_out_buffer_type) :: output 169 | 170 | ! Create the input and output buffers. They may be any size, but 171 | ! we recommend using these functions to size them. Performance will 172 | ! only suffer significantly for very tiny buffers. 173 | buf_in_sz = zstd_c_stream_in_size() 174 | buf_out_sz = zstd_c_stream_out_size() 175 | 176 | allocate (character(len=buf_in_sz) :: buf_in) 177 | allocate (character(len=buf_out_sz) :: buf_out) 178 | 179 | c_ctx = zstd_create_c_ctx() 180 | 181 | if (.not. c_associated(c_ctx)) then 182 | print '("zstd_create_c_ctx")' 183 | success = .false. 184 | exit c_block 185 | end if 186 | 187 | level = zstd_default_c_level() 188 | stat = zstd_c_ctx_set_parameter(c_ctx, ZSTD_C_COMPRESSIONLEVEL, level) 189 | 190 | if (zstd_is_error(stat)) then 191 | print '("zstd_c_ctx_set_parameter: ", a)', zstd_get_error_name(stat) 192 | success = .false. 193 | end if 194 | 195 | stat = zstd_c_ctx_set_parameter(c_ctx, ZSTD_C_CHECKSUMFLAG, 1) 196 | 197 | if (zstd_is_error(stat)) then 198 | print '("zstd_c_ctx_set_parameter: ", a)', zstd_get_error_name(stat) 199 | success = .false. 200 | end if 201 | 202 | pos = 0 203 | to_read = buf_in_sz 204 | 205 | do 206 | nbytes = test_read(buf_in, pos, to_read, src1) 207 | last_chunk = (nbytes < to_read) 208 | 209 | ! Select the flush mode. If the read may not be finished 210 | ! (nbytes == to_read) we use ZSTD_E_CONTINUE. If this is the 211 | ! last chunk, we use ZSTD_E_END. Zstd optimises the case where 212 | ! the first flush mode is ZSTD_E_END, since it knows it is 213 | ! compressing the entire source in one pass. 214 | if (last_chunk) then 215 | mode = ZSTD_E_END 216 | else 217 | mode = ZSTD_E_CONTINUE 218 | end if 219 | 220 | ! Set the input buffer to what we just read. We compress until 221 | ! the input buffer is empty, each time flushing the output. 222 | input = zstd_in_buffer_type(c_loc(buf_in), nbytes, 0) 223 | finished = .false. 224 | 225 | do while (.not. finished) 226 | ! Compress into the output buffer and write all of the output to 227 | ! the file so we can reuse the buffer next iteration. 228 | output = zstd_out_buffer_type(c_loc(buf_out), buf_out_sz, 0) 229 | 230 | remaining = zstd_compress_stream2(c_ctx, output, input, mode) 231 | 232 | if (zstd_is_error(remaining)) then 233 | print '("zstd_compress_stream2: ", a)', zstd_get_error_name(remaining) 234 | success = .false. 235 | exit 236 | end if 237 | 238 | ! Add compressed chunk to destination string. Alternatively, 239 | ! we could also write the chunk to file. 240 | dst = dst // buf_out(:output%pos) 241 | 242 | ! If we're on the last chunk we're finished when zstd returns 0, 243 | ! which means its consumed all the input AND finished the frame. 244 | ! Otherwise, we're finished when we've consumed all the input. 245 | if (last_chunk) then 246 | finished = (remaining == 0) 247 | else 248 | finished = (input%pos == input%size) 249 | end if 250 | end do 251 | 252 | if (input%pos /= input%size) then 253 | print '("zstd only returns 0 when the input is completely consumed")' 254 | success = .false. 255 | exit 256 | end if 257 | 258 | if (last_chunk) exit 259 | end do 260 | 261 | stat = zstd_free_c_ctx(c_ctx) 262 | end block c_block 263 | 264 | if (.not. success) return 265 | 266 | ! Decompression: dst -> src2. 267 | d_block: block 268 | character(len=:), allocatable, target :: buf_in, buf_out 269 | 270 | integer(kind=c_size_t) :: buf_in_sz, buf_out_sz 271 | integer(kind=c_size_t) :: last_stat, nbytes, pos, to_read 272 | logical :: is_empty 273 | type(c_ptr) :: d_ctx 274 | type(zstd_in_buffer_type) :: input 275 | type(zstd_out_buffer_type) :: output 276 | 277 | buf_in_sz = zstd_d_stream_in_size() 278 | buf_out_sz = zstd_d_stream_out_size() 279 | 280 | allocate (character(len=buf_in_sz) :: buf_in) 281 | allocate (character(len=buf_out_sz) :: buf_out) 282 | 283 | d_ctx = zstd_create_d_ctx() 284 | 285 | if (.not. c_associated(d_ctx)) then 286 | print '("zstd_create_d_ctx")' 287 | success = .false. 288 | exit d_block 289 | end if 290 | 291 | pos = 0 292 | to_read = buf_in_sz 293 | last_stat = 0 294 | is_empty = .true. 295 | 296 | ! This loop assumes that the input file is one or more concatenated zstd 297 | ! streams. This example won't work if there is trailing non-zstd data at 298 | ! the end, but streaming decompression in general handles this case. 299 | ! zstd_decompress_stream() returns 0 exactly when the frame is completed, 300 | ! and doesn't consume input after the frame. 301 | do 302 | nbytes = test_read(buf_in, pos, to_read, dst) 303 | if (nbytes == 0) exit 304 | is_empty = .false. 305 | 306 | input = zstd_in_buffer_type(c_loc(buf_in), nbytes, 0) 307 | 308 | ! Given a valid frame, zstd won't consume the last byte of the frame 309 | ! until it has flushed all of the decompressed data of the frame. 310 | ! Therefore, instead of checking if the return code is 0, we can 311 | ! decompress just check if input%pos < input%size. 312 | do while (input%pos < input%size) 313 | output = zstd_out_buffer_type(c_loc(buf_out), buf_out_sz, 0) 314 | 315 | ! The return code is zero if the frame is complete, but there may 316 | ! be multiple frames concatenated together. Zstd will automatically 317 | ! reset the context when a frame is complete. Still, calling 318 | ! zstd_d_ctx_reset() can be useful to reset the context to a clean 319 | ! state, for instance if the last decompression call returned an 320 | ! error. 321 | stat = zstd_decompress_stream(d_ctx, output, input) 322 | 323 | if (zstd_is_error(stat)) then 324 | print '("zstd_decompress_stream: ", a)', zstd_get_error_name(stat) 325 | success = .false. 326 | exit 327 | end if 328 | 329 | src2 = src2 // buf_out(:output%pos) 330 | last_stat = stat 331 | end do 332 | end do 333 | 334 | if (is_empty) then 335 | print '("input is empty")' 336 | success = .false. 337 | end if 338 | 339 | if (last_stat /= 0) then 340 | ! The last return value from zstd_decompress_stream did not end on a 341 | ! frame, but we reached the end of the file! We assume this is an 342 | ! error, and the input was truncated. 343 | print '("EOF before end of stream: ", i0)', last_stat 344 | success = .false. 345 | end if 346 | 347 | stat = zstd_free_d_ctx(d_ctx) 348 | end block d_block 349 | 350 | print '("src1 length: ", i0)', len(src1) 351 | print '("src2 length: ", i0)', len(src2) 352 | print '("dst length: ", i0)', len(dst) 353 | 354 | if (src1 /= src2) then 355 | print '("data mismatch")' 356 | success = .false. 357 | end if 358 | end function test_stream 359 | end program main 360 | -------------------------------------------------------------------------------- /COVERAGE.md: -------------------------------------------------------------------------------- 1 | # Coverage 2 | 3 | | C function | Fortran interface | Notes | 4 | |--------------------------------------------|-----------------------------------|----------------------------| 5 | | `ZSTD_CCtxParams_getParameter` | | | 6 | | `ZSTD_CCtxParams_init` | | | 7 | | `ZSTD_CCtxParams_init_advanced` | | | 8 | | `ZSTD_CCtxParams_registerSequenceProducer` | | | 9 | | `ZSTD_CCtxParams_reset` | | | 10 | | `ZSTD_CCtxParams_setParameter` | | | 11 | | `ZSTD_CCtx_getParameter` | | | 12 | | `ZSTD_CCtx_loadDictionary` | | | 13 | | `ZSTD_CCtx_loadDictionary_advanced` | | | 14 | | `ZSTD_CCtx_loadDictionary_byReference` | | | 15 | | `ZSTD_CCtx_refCDict` | | | 16 | | `ZSTD_CCtx_refPrefix` | | | 17 | | `ZSTD_CCtx_refPrefix_advanced` | | | 18 | | `ZSTD_CCtx_refThreadPool` | | | 19 | | `ZSTD_CCtx_reset` | `zstd_c_ctx_reset` | | 20 | | `ZSTD_CCtx_setCParams` | | | 21 | | `ZSTD_CCtx_setFParams` | | | 22 | | `ZSTD_CCtx_setParameter` | `zstd_c_ctx_set_parameter` | | 23 | | `ZSTD_CCtx_setParametersUsingCCtxParams` | | | 24 | | `ZSTD_CCtx_setParams` | | | 25 | | `ZSTD_CCtx_setPledgedSrcSize` | `zstd_c_ctx_set_pledged_src_size` | | 26 | | `ZSTD_CStreamInSize` | `zstd_c_stream_in_size` | | 27 | | `ZSTD_CStreamOutSize` | `zstd_c_stream_out_size` | | 28 | | `ZSTD_DCtx_getParameter` | | | 29 | | `ZSTD_DCtx_loadDictionary` | | | 30 | | `ZSTD_DCtx_loadDictionary_advanced` | | | 31 | | `ZSTD_DCtx_loadDictionary_byReference` | | | 32 | | `ZSTD_DCtx_refDDict` | | | 33 | | `ZSTD_DCtx_refPrefix` | | | 34 | | `ZSTD_DCtx_refPrefix_advanced` | | | 35 | | `ZSTD_DCtx_reset` | `zstd_d_ctx_reset` | | 36 | | `ZSTD_DCtx_setFormat` | | deprecated | 37 | | `ZSTD_DCtx_setMaxWindowSize` | | | 38 | | `ZSTD_DCtx_setParameter` | `zstd_d_ctx_set_parameter` | | 39 | | `ZSTD_DStreamInSize` | `zstd_d_stream_in_size` | | 40 | | `ZSTD_DStreamOutSize` | `zstd_d_stream_out_size` | | 41 | | `ZSTD_adjustCParams` | | | 42 | | `ZSTD_cParam_getBounds` | `zstd_c_param_get_bounds` | | 43 | | `ZSTD_checkCParams` | | | 44 | | `ZSTD_compress` | `zstd_compress` | | 45 | | `ZSTD_compress2` | `zstd_compress2` | | 46 | | `ZSTD_compressBegin` | | deprecated | 47 | | `ZSTD_compressBegin_advanced` | | deprecated | 48 | | `ZSTD_compressBegin_usingCDict` | | deprecated | 49 | | `ZSTD_compressBegin_usingCDict_advanced` | | deprecated | 50 | | `ZSTD_compressBegin_usingDict` | | deprecated | 51 | | `ZSTD_compressBlock` | | deprecated | 52 | | `ZSTD_compressBound` | `zstd_compress_bound` | | 53 | | `ZSTD_compressCCtx` | `zstd_compress_c_ctx` | | 54 | | `ZSTD_compressContinue` | | deprecated | 55 | | `ZSTD_compressEnd` | | deprecated | 56 | | `ZSTD_compressSequences` | | | 57 | | `ZSTD_compressStream` | `zstd_compress_stream` | deprecated | 58 | | `ZSTD_compressStream2` | `zstd_compress_stream2` | | 59 | | `ZSTD_compressStream2_simpleArgs` | | | 60 | | `ZSTD_compress_advanced` | | deprecated | 61 | | `ZSTD_compress_usingCDict` | | | 62 | | `ZSTD_compress_usingCDict_advanced` | | deprecated | 63 | | `ZSTD_compress_usingDict` | | | 64 | | `ZSTD_copyCCtx` | | deprecated | 65 | | `ZSTD_copyDCtx` | | deprecated | 66 | | `ZSTD_createCCtx` | `zstd_create_c_ctx` | | 67 | | `ZSTD_createCCtxParams` | | | 68 | | `ZSTD_createCCtx_advanced` | | | 69 | | `ZSTD_createCDict` | | | 70 | | `ZSTD_createCDict_advanced` | | | 71 | | `ZSTD_createCDict_advanced2` | | deprecated | 72 | | `ZSTD_createCDict_byReference` | | | 73 | | `ZSTD_createCStream` | `zstd_create_c_stream` | | 74 | | `ZSTD_createCStream_advanced` | | | 75 | | `ZSTD_createDCtx` | `zstd_create_d_ctx` | | 76 | | `ZSTD_createDCtx_advanced` | | | 77 | | `ZSTD_createDDict` | | | 78 | | `ZSTD_createDDict_advanced` | | deprecated | 79 | | `ZSTD_createDDict_byReference` | | | 80 | | `ZSTD_createDStream` | `zstd_create_d_stream` | | 81 | | `ZSTD_createDStream_advanced` | | | 82 | | `ZSTD_createThreadPool` | | | 83 | | `ZSTD_dParam_getBounds` | `zstd_d_param_get_bounds` | | 84 | | `ZSTD_decodingBufferSize_min` | | | 85 | | `ZSTD_decompressBegin_usingDDict` | | | 86 | | `ZSTD_decompressBegin_usingDict` | | | 87 | | `ZSTD_decompressBegin` | | | 88 | | `ZSTD_decompressBlock` | | deprecated | 89 | | `ZSTD_decompressBound` | `zstd_decompress_bound` | | 90 | | `ZSTD_decompressContinue` | | | 91 | | `ZSTD_decompressDCtx` | `zstd_decompress_d_ctx` | | 92 | | `ZSTD_decompressStream` | `zstd_decompress_stream` | | 93 | | `ZSTD_decompressStream_simpleArgs` | | | 94 | | `ZSTD_decompress_usingDDict` | | | 95 | | `ZSTD_decompress_usingDict` | | | 96 | | `ZSTD_decompress` | `zstd_decompress` | | 97 | | `ZSTD_decompressionMargin` | | | 98 | | `ZSTD_defaultCLevel` | `zstd_default_c_level` | | 99 | | `ZSTD_endStream` | `zstd_end_stream` | deprecated | 100 | | `ZSTD_estimateCCtxSize` | | | 101 | | `ZSTD_estimateCCtxSize_usingCCtxParams` | | | 102 | | `ZSTD_estimateCCtxSize_usingCParams` | | | 103 | | `ZSTD_estimateCDictSize` | | | 104 | | `ZSTD_estimateCDictSize_advanced` | | | 105 | | `ZSTD_estimateCStreamSize` | | | 106 | | `ZSTD_estimateCStreamSize_usingCCtxParams` | | | 107 | | `ZSTD_estimateCStreamSize_usingCParams` | | | 108 | | `ZSTD_estimateDCtxSize` | | | 109 | | `ZSTD_estimateDDictSize` | | | 110 | | `ZSTD_estimateDStreamSize` | | | 111 | | `ZSTD_estimateDStreamSize_fromFrame` | | | 112 | | `ZSTD_findDecompressedSize` | `zstd_find_decompressed_size` | | 113 | | `ZSTD_findFrameCompressedSize` | `zstd_find_frame_compressed_size` | | 114 | | `ZSTD_flushStream` | `zstd_flush_stream` | deprecated | 115 | | `ZSTD_frameHeaderSize` | | | 116 | | `ZSTD_freeCCtxParams` | | | 117 | | `ZSTD_freeCCtx` | `zstd_free_c_ctx` | wrapper | 118 | | `ZSTD_freeCDict` | | | 119 | | `ZSTD_freeCStream` | `zstd_free_c_stream` | wrapper | 120 | | `ZSTD_freeDCtx` | `zstd_free_d_ctx` | wrapper | 121 | | `ZSTD_freeDDict` | | | 122 | | `ZSTD_freeDStream` | `zstd_free_d_stream` | wrapper | 123 | | `ZSTD_freeThreadPool` | | | 124 | | `ZSTD_generateSequences` | | deprecated | 125 | | `ZSTD_getBlockSize` | | deprecated | 126 | | `ZSTD_getCParams` | | | 127 | | `ZSTD_getDecompressedSize` | `zstd_get_decompressed_size` | deprecated | 128 | | `ZSTD_getDictID_fromCDict` | | | 129 | | `ZSTD_getDictID_fromDDict` | | | 130 | | `ZSTD_getDictID_fromDict` | | | 131 | | `ZSTD_getDictID_fromFrame` | | | 132 | | `ZSTD_getErrorName` | `zstd_get_error_name` | wrapper | 133 | | `ZSTD_getFrameContentSize` | `zstd_get_frame_content_size` | | 134 | | `ZSTD_getFrameHeader` | | | 135 | | `ZSTD_getFrameHeader_advanced` | | | 136 | | `ZSTD_getFrameProgression` | | | 137 | | `ZSTD_getParams` | | | 138 | | `ZSTD_initCStream` | `zstd_init_c_stream` | | 139 | | `ZSTD_initCStream_advanced` | | deprecated | 140 | | `ZSTD_initCStream_srcSize` | | deprecated | 141 | | `ZSTD_initCStream_usingCDict` | | deprecated | 142 | | `ZSTD_initCStream_usingCDict_advanced` | | deprecated | 143 | | `ZSTD_initCStream_usingDDict` | | deprecated | 144 | | `ZSTD_initCStream_usingDict` | | deprecated | 145 | | `ZSTD_initDStream` | `zstd_init_d_stream` | | 146 | | `ZSTD_initDStream_usingDDict` | | deprecated | 147 | | `ZSTD_initDStream_usingDict` | | deprecated | 148 | | `ZSTD_initStaticCCtx` | | | 149 | | `ZSTD_initStaticCDict` | | | 150 | | `ZSTD_initStaticCStream` | | | 151 | | `ZSTD_initStaticDCtx` | | | 152 | | `ZSTD_initStaticDDict` | | | 153 | | `ZSTD_initStaticDStream` | | | 154 | | `ZSTD_insertBlock` | | deprecated | 155 | | `ZSTD_isError` | `zstd_is_error` | wrapper, returns _logical_ | 156 | | `ZSTD_isFrame` | | | 157 | | `ZSTD_isSkippableFrame` | | | 158 | | `ZSTD_maxCLevel` | `zstd_max_c_level` | | 159 | | `ZSTD_mergeBlockDelimiters` | | | 160 | | `ZSTD_minCLevel` | `zstd_min_c_level` | | 161 | | `ZSTD_nextInputType` | | | 162 | | `ZSTD_nextSrcSizeToDecompress` | | | 163 | | `ZSTD_readSkippableFrame` | | | 164 | | `ZSTD_registerSequenceProducer` | | | 165 | | `ZSTD_resetCStream` | | deprecated | 166 | | `ZSTD_resetDStream` | | deprecated | 167 | | `ZSTD_sequenceBound` | | | 168 | | `ZSTD_sizeof_CCtx` | | | 169 | | `ZSTD_sizeof_CDict` | | | 170 | | `ZSTD_sizeof_CStream` | | | 171 | | `ZSTD_sizeof_DCtx` | | | 172 | | `ZSTD_sizeof_DDict` | | | 173 | | `ZSTD_sizeof_DStream` | | | 174 | | `ZSTD_toFlushNow` | | | 175 | | `ZSTD_versionNumber` | `zstd_version_number` | | 176 | | `ZSTD_versionString` | `zstd_version_string` | wrapper | 177 | | `ZSTD_writeSkippableFrame` | | | 178 | -------------------------------------------------------------------------------- /src/zstd.F90: -------------------------------------------------------------------------------- 1 | ! zstd.F90 2 | ! 3 | ! Author: Philipp Engel 4 | ! Licence: ISC 5 | module zstd 6 | !! Fortran 2018 interface bindings to Zstandard (zstd). 7 | use, intrinsic :: iso_c_binding, only: c_associated, c_f_pointer, c_loc, & 8 | c_char, c_int, c_long_long, c_size_t, & 9 | c_ptr, c_null_char, c_null_ptr 10 | #if HAS_UNSIGNED 11 | 12 | use, intrinsic :: iso_c_binding, only: c_unsigned, c_unsigned_long_long 13 | 14 | #endif 15 | implicit none (type, external) 16 | private 17 | 18 | public :: c_associated 19 | public :: c_f_pointer 20 | public :: c_loc 21 | 22 | public :: c_char 23 | public :: c_int 24 | public :: c_long_long 25 | public :: c_size_t 26 | public :: c_ptr 27 | public :: c_null_char 28 | public :: c_null_ptr 29 | 30 | #if HAS_UNSIGNED 31 | 32 | public :: c_unsigned 33 | public :: c_unsigned_long_long 34 | 35 | #else 36 | 37 | integer, parameter, public :: c_unsigned = c_int 38 | integer, parameter, public :: c_unsigned_long_long = c_long_long 39 | 40 | #endif 41 | 42 | integer(kind=c_int), parameter, public :: ZSTD_BLOCKSIZELOG_MAX = 17 43 | integer(kind=c_size_t), parameter, public :: ZSTD_BLOCKSIZE_MAX = shiftl(1, ZSTD_BLOCKSIZELOG_MAX) 44 | 45 | integer(kind=c_unsigned_long_long), parameter, public :: ZSTD_CONTENTSIZE_UNKNOWN = -1 46 | integer(kind=c_unsigned_long_long), parameter, public :: ZSTD_CONTENTSIZE_ERROR = -2 47 | 48 | ! ZSTD_strategy 49 | integer(kind=c_int), parameter, public :: ZSTD_FAST = 1 50 | integer(kind=c_int), parameter, public :: ZSTD_DFAST = 2 51 | integer(kind=c_int), parameter, public :: ZSTD_GREEDY = 3 52 | integer(kind=c_int), parameter, public :: ZSTD_LAZY = 4 53 | integer(kind=c_int), parameter, public :: ZSTD_LAZY2 = 5 54 | integer(kind=c_int), parameter, public :: ZSTD_BTLAZY2 = 6 55 | integer(kind=c_int), parameter, public :: ZSTD_BTOPT = 7 56 | integer(kind=c_int), parameter, public :: ZSTD_BTULTRA = 8 57 | integer(kind=c_int), parameter, public :: ZSTD_BTULTRA2 = 9 58 | 59 | ! ZSTD_cParameter 60 | integer(kind=c_int), parameter, public :: ZSTD_C_COMPRESSIONLEVEL = 100 61 | integer(kind=c_int), parameter, public :: ZSTD_C_WINDOWLOG = 101 62 | integer(kind=c_int), parameter, public :: ZSTD_C_HASHLOG = 102 63 | integer(kind=c_int), parameter, public :: ZSTD_C_SEARCHLOG = 104 64 | integer(kind=c_int), parameter, public :: ZSTD_C_MINMATCH = 105 65 | integer(kind=c_int), parameter, public :: ZSTD_C_TARGETLENGTH = 106 66 | integer(kind=c_int), parameter, public :: ZSTD_C_STRATEGY = 107 67 | integer(kind=c_int), parameter, public :: ZSTD_C_TARGETCBLOCKSIZE = 130 68 | integer(kind=c_int), parameter, public :: ZSTD_C_ENABLELONGDISTANCEMATCHING = 160 69 | integer(kind=c_int), parameter, public :: ZSTD_C_LDMHASHLOG = 161 70 | integer(kind=c_int), parameter, public :: ZSTD_C_LDMMINMATCH = 162 71 | integer(kind=c_int), parameter, public :: ZSTD_C_LDMBUCKETSIZELOG = 163 72 | integer(kind=c_int), parameter, public :: ZSTD_C_LDMHASHRATELOG = 164 73 | integer(kind=c_int), parameter, public :: ZSTD_C_CONTENTSIZEFLAG = 200 74 | integer(kind=c_int), parameter, public :: ZSTD_C_CHECKSUMFLAG = 201 75 | integer(kind=c_int), parameter, public :: ZSTD_C_DICTIDFLAG = 202 76 | integer(kind=c_int), parameter, public :: ZSTD_C_NBWORKERS = 400 77 | integer(kind=c_int), parameter, public :: ZSTD_C_JOBSIZE = 401 78 | integer(kind=c_int), parameter, public :: ZSTD_C_OVERLAPLOG = 402 79 | 80 | ! ZSTD_dParameter 81 | integer(kind=c_int), parameter, public :: ZSTD_D_WINDOWLOGMAX = 100 82 | 83 | ! ZSTD_EndDirective 84 | integer(kind=c_int), parameter, public :: ZSTD_E_CONTINUE = 0 85 | integer(kind=c_int), parameter, public :: ZSTD_E_FLUSH = 1 86 | integer(kind=c_int), parameter, public :: ZSTD_E_END = 2 87 | 88 | ! ZSTD_ResetDirective 89 | integer(kind=c_int), parameter, public :: ZSTD_RESET_SESSION_ONLY = 1 90 | integer(kind=c_int), parameter, public :: ZSTD_RESET_PARAMETERS = 2 91 | integer(kind=c_int), parameter, public :: ZSTD_RESET_SESSION_AND_PARAMETERS = 3 92 | 93 | ! ZSTD_bounds 94 | type, bind(c), public :: zstd_bounds_type 95 | integer(kind=c_size_t) :: error = 0 96 | integer(kind=c_int) :: lower_bound = 0 97 | integer(kind=c_int) :: upper_bound = 0 98 | end type zstd_bounds_type 99 | 100 | ! ZSTD_inBuffer 101 | type, bind(c), public :: zstd_in_buffer_type 102 | type(c_ptr) :: src = c_null_ptr 103 | integer(kind=c_size_t) :: size = 0 104 | integer(kind=c_size_t) :: pos = 0 105 | end type zstd_in_buffer_type 106 | 107 | ! ZSTD_outBuffer 108 | type, bind(c), public :: zstd_out_buffer_type 109 | type(c_ptr) :: dst = c_null_ptr 110 | integer(kind=c_size_t) :: size = 0 111 | integer(kind=c_size_t) :: pos = 0 112 | end type zstd_out_buffer_type 113 | 114 | interface 115 | ! size_t ZSTD_CCtx_reset(ZSTD_CCtx *cctx, ZSTD_ResetDirective reset) 116 | function zstd_c_ctx_reset(c_ctx, reset) bind(c, name='ZSTD_CCtx_reset') 117 | import :: c_int, c_ptr, c_size_t 118 | implicit none 119 | type(c_ptr), intent(in), value :: c_ctx 120 | integer(kind=c_int), intent(in), value :: reset 121 | integer(kind=c_size_t) :: zstd_c_ctx_reset 122 | end function zstd_c_ctx_reset 123 | 124 | ! size_t ZSTD_CCtx_setParameter(ZSTD_CCtx *cctx, ZSTD_cParameter param, int value) 125 | function zstd_c_ctx_set_parameter(c_ctx, param, value) bind(c, name='ZSTD_CCtx_setParameter') 126 | import :: c_int, c_ptr, c_size_t 127 | implicit none 128 | type(c_ptr), intent(in), value :: c_ctx 129 | integer(kind=c_int), intent(in), value :: param 130 | integer(kind=c_int), intent(in), value :: value 131 | integer(kind=c_size_t) :: zstd_c_ctx_set_parameter 132 | end function zstd_c_ctx_set_parameter 133 | 134 | ! size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx *cctx, unsigned long long pledgedSrcSize) 135 | function zstd_c_ctx_set_pledged_src_size(c_ctx, pledged_src_size) bind(c, name='ZSTD_CCtx_setPledgedSrcSize') 136 | import :: c_ptr, c_size_t, c_unsigned_long_long 137 | implicit none 138 | type(c_ptr), intent(in), value :: c_ctx 139 | integer(kind=c_unsigned_long_long), intent(in), value :: pledged_src_size 140 | integer(kind=c_size_t) :: zstd_c_ctx_set_pledged_src_size 141 | end function zstd_c_ctx_set_pledged_src_size 142 | 143 | ! ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter cParam) 144 | function zstd_c_param_get_bounds(c_param) bind(c, name='ZSTD_cParam_getBounds') 145 | import :: c_int, zstd_bounds_type 146 | implicit none 147 | integer(kind=c_int), intent(in), value :: c_param 148 | type(zstd_bounds_type) :: zstd_c_param_get_bounds 149 | end function zstd_c_param_get_bounds 150 | 151 | ! size_t ZSTD_compress(void *dst, size_t dstCapacity, const void *src, size_t srcSize, int compressionLevel) 152 | function zstd_compress(dst, dst_capacity, src, src_size, compression_level) bind(c, name='ZSTD_compress') 153 | import :: c_int, c_size_t 154 | implicit none 155 | type(*), intent(inout) :: dst 156 | integer(kind=c_size_t), intent(in), value :: dst_capacity 157 | type(*), intent(inout) :: src 158 | integer(kind=c_size_t), intent(in), value :: src_size 159 | integer(kind=c_int), intent(in), value :: compression_level 160 | integer(kind=c_size_t) :: zstd_compress 161 | end function zstd_compress 162 | 163 | ! size_t ZSTD_compress2(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize) 164 | function zstd_compress2(c_ctx, dst, dst_capacity, src, src_size) bind(c, name='ZSTD_compress2') 165 | import :: c_ptr, c_size_t 166 | implicit none 167 | type(c_ptr), intent(in), value :: c_ctx 168 | type(*), intent(inout) :: dst 169 | integer(kind=c_size_t), intent(in), value :: dst_capacity 170 | type(*), intent(inout) :: src 171 | integer(kind=c_size_t), intent(in), value :: src_size 172 | integer(kind=c_size_t) :: zstd_compress2 173 | end function zstd_compress2 174 | 175 | ! size_t ZSTD_compressBound(size_t srcSize) 176 | function zstd_compress_bound(src_size) bind(c, name='ZSTD_compressBound') 177 | import :: c_size_t 178 | integer(kind=c_size_t), intent(in), value :: src_size 179 | integer(kind=c_size_t) :: zstd_compress_bound 180 | end function zstd_compress_bound 181 | 182 | ! size_t ZSTD_compressCCtx(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, int compressionLevel) 183 | function zstd_compress_c_ctx(c_ctx, dst, dst_capacity, src, src_size, compression_level) bind(c, name='ZSTD_compressCCtx') 184 | import :: c_int, c_ptr, c_size_t 185 | implicit none 186 | type(c_ptr), intent(in), value :: c_ctx 187 | type(*), intent(inout) :: dst 188 | integer(kind=c_size_t), intent(in), value :: dst_capacity 189 | type(*), intent(inout) :: src 190 | integer(kind=c_size_t), intent(in), value :: src_size 191 | integer(kind=c_int), intent(in), value :: compression_level 192 | integer(kind=c_size_t) :: zstd_compress_c_ctx 193 | end function zstd_compress_c_ctx 194 | 195 | ! size_t ZSTD_compressStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output, ZSTD_inBuffer *input) 196 | function zstd_compress_stream(zcs, output, input) bind(c, name='ZSTD_compressStream') 197 | !! Deprecated. 198 | import :: c_ptr, c_size_t, zstd_in_buffer_type, zstd_out_buffer_type 199 | implicit none 200 | type(c_ptr), intent(in), value :: zcs 201 | type(zstd_out_buffer_type), intent(inout) :: output 202 | type(zstd_in_buffer_type), intent(inout) :: input 203 | integer(kind=c_size_t) :: zstd_compress_stream 204 | end function zstd_compress_stream 205 | 206 | ! size_t ZSTD_compressStream2(ZSTD_CCtx *cctx, ZSTD_outBuffer *output, ZSTD_inBuffer *input, ZSTD_EndDirective endOp) 207 | function zstd_compress_stream2(c_ctx, output, input, end_op) bind(c, name='ZSTD_compressStream2') 208 | import :: c_int, c_ptr, c_size_t, zstd_in_buffer_type, zstd_out_buffer_type 209 | implicit none 210 | type(c_ptr), intent(in), value :: c_ctx 211 | type(zstd_out_buffer_type), intent(inout) :: output 212 | type(zstd_in_buffer_type), intent(inout) :: input 213 | integer(kind=c_int), intent(in), value :: end_op 214 | integer(kind=c_size_t) :: zstd_compress_stream2 215 | end function zstd_compress_stream2 216 | 217 | ! ZSTD_CCtx *ZSTD_createCCtx(void) 218 | function zstd_create_c_ctx() bind(c, name='ZSTD_createCCtx') 219 | import :: c_ptr 220 | implicit none 221 | type(c_ptr) :: zstd_create_c_ctx 222 | end function zstd_create_c_ctx 223 | 224 | ! ZSTD_CStream *ZSTD_createCStream(void) 225 | function zstd_create_c_stream() bind(c, name='ZSTD_createCStream') 226 | import :: c_ptr 227 | implicit none 228 | type(c_ptr) :: zstd_create_c_stream 229 | end function zstd_create_c_stream 230 | 231 | ! ZSTD_DCtx *ZSTD_createDCtx(void) 232 | function zstd_create_d_ctx() bind(c, name='ZSTD_createDCtx') 233 | import :: c_ptr 234 | implicit none 235 | type(c_ptr) :: zstd_create_d_ctx 236 | end function zstd_create_d_ctx 237 | 238 | ! ZSTD_DStream *ZSTD_createDStream(void) 239 | function zstd_create_d_stream() bind(c, name='ZSTD_createDStream') 240 | import :: c_ptr 241 | implicit none 242 | type(c_ptr) :: zstd_create_d_stream 243 | end function zstd_create_d_stream 244 | 245 | ! size_t ZSTD_CStreamInSize(void) 246 | function zstd_c_stream_in_size() bind(c, name='ZSTD_CStreamInSize') 247 | import :: c_size_t 248 | integer(kind=c_size_t) :: zstd_c_stream_in_size 249 | end function zstd_c_stream_in_size 250 | 251 | ! size_t ZSTD_CStreamOutSize(void) 252 | function zstd_c_stream_out_size() bind(c, name='ZSTD_CStreamOutSize') 253 | import :: c_size_t 254 | integer(kind=c_size_t) :: zstd_c_stream_out_size 255 | end function zstd_c_stream_out_size 256 | 257 | ! size_t ZSTD_DCtx_reset(ZSTD_DCtx *dctx, ZSTD_ResetDirective reset) 258 | function zstd_d_ctx_reset(d_ctx, reset) bind(c, name='ZSTD_DCtx_reset') 259 | import :: c_int, c_ptr, c_size_t 260 | implicit none 261 | type(c_ptr), intent(in), value :: d_ctx 262 | integer(kind=c_int), intent(in), value :: reset 263 | integer(kind=c_size_t) :: zstd_d_ctx_reset 264 | end function zstd_d_ctx_reset 265 | 266 | ! size_t ZSTD_DCtx_setParameter(ZSTD_DCtx *dctx, ZSTD_dParameter param, int value) 267 | function zstd_d_ctx_set_parameter(d_ctx, param, value) bind(c, name='ZSTD_DCtx_setParameter') 268 | import :: c_int, c_ptr, c_size_t 269 | implicit none 270 | type(c_ptr), intent(in), value :: d_ctx 271 | integer(kind=c_int), intent(in), value :: param 272 | integer(kind=c_int), intent(in), value :: value 273 | integer(kind=c_size_t) :: zstd_d_ctx_set_parameter 274 | end function zstd_d_ctx_set_parameter 275 | 276 | ! size_t ZSTD_DStreamInSize(void) 277 | function zstd_d_stream_in_size() bind(c, name='ZSTD_DStreamInSize') 278 | import :: c_size_t 279 | implicit none 280 | integer(kind=c_size_t) :: zstd_d_stream_in_size 281 | end function zstd_d_stream_in_size 282 | 283 | ! size_t ZSTD_DStreamOutSize(void) 284 | function zstd_d_stream_out_size() bind(c, name='ZSTD_DStreamOutSize') 285 | import :: c_size_t 286 | implicit none 287 | integer(kind=c_size_t) :: zstd_d_stream_out_size 288 | end function zstd_d_stream_out_size 289 | 290 | ! size_t ZSTD_decompress(void *dst, size_t dstCapacity, const void *src, size_t compressedSize) 291 | function zstd_decompress(dst, dst_capacity, src, compressed_size) bind(c, name='ZSTD_decompress') 292 | import :: c_size_t 293 | implicit none 294 | type(*), intent(inout) :: dst 295 | integer(kind=c_size_t), intent(in), value :: dst_capacity 296 | type(*), intent(inout) :: src 297 | integer(kind=c_size_t), intent(in), value :: compressed_size 298 | integer(kind=c_size_t) :: zstd_decompress 299 | end function zstd_decompress 300 | 301 | ! unsigned long long ZSTD_decompressBound(const void *src, size_t srcSize) 302 | function zstd_decompress_bound(src, src_size) bind(c, name='ZSTD_decompressBound') 303 | import :: c_size_t, c_unsigned_long_long 304 | implicit none 305 | type(*), intent(inout) :: src 306 | integer(kind=c_size_t), intent(in), value :: src_size 307 | integer(kind=c_unsigned_long_long) :: zstd_decompress_bound 308 | end function zstd_decompress_bound 309 | 310 | ! size_t ZSTD_decompressDCtx(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize) 311 | function zstd_decompress_d_ctx(d_ctx, dst, dst_capacity, src, src_size) bind(c, name='ZSTD_decompressDCtx') 312 | import :: c_ptr, c_size_t 313 | implicit none 314 | type(c_ptr), intent(in), value :: d_ctx 315 | type(*), intent(inout) :: dst 316 | integer(kind=c_size_t), intent(in), value :: dst_capacity 317 | type(*), intent(inout) :: src 318 | integer(kind=c_size_t), intent(in), value :: src_size 319 | integer(kind=c_size_t) :: zstd_decompress_d_ctx 320 | end function zstd_decompress_d_ctx 321 | 322 | ! size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inBuffer *input) 323 | function zstd_decompress_stream(zds, output, input) bind(c, name='ZSTD_decompressStream') 324 | import :: c_ptr, c_size_t, zstd_in_buffer_type, zstd_out_buffer_type 325 | implicit none 326 | type(c_ptr), intent(in), value :: zds 327 | type(zstd_out_buffer_type), intent(inout) :: output 328 | type(zstd_in_buffer_type), intent(inout) :: input 329 | integer(kind=c_size_t) :: zstd_decompress_stream 330 | end function zstd_decompress_stream 331 | 332 | ! int ZSTD_defaultCLevel(void) 333 | function zstd_default_c_level() bind(c, name='ZSTD_defaultCLevel') 334 | import :: c_int 335 | implicit none 336 | integer(kind=c_int) :: zstd_default_c_level 337 | end function zstd_default_c_level 338 | 339 | ! ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) 340 | function zstd_d_param_get_bounds(d_param) bind(c, name='ZSTD_dParam_getBounds') 341 | import :: c_int, zstd_bounds_type 342 | implicit none 343 | integer(kind=c_int), intent(in), value :: d_param 344 | type(zstd_bounds_type) :: zstd_d_param_get_bounds 345 | end function zstd_d_param_get_bounds 346 | 347 | ! size_t ZSTD_endStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output) 348 | function zstd_end_stream(zcs, output) bind(c, name='ZSTD_endStream') 349 | !! Deprecated. 350 | import :: c_ptr, c_size_t, zstd_out_buffer_type 351 | implicit none 352 | type(c_ptr), intent(in), value :: zcs 353 | type(zstd_out_buffer_type), intent(inout) :: output 354 | integer(kind=c_size_t) :: zstd_end_stream 355 | end function zstd_end_stream 356 | 357 | ! unsigned long long ZSTD_findDecompressedSize(const void *src, size_t srcSize) 358 | function zstd_find_decompressed_size(src, src_size) bind(c, name='ZSTD_findDecompressedSize') 359 | import :: c_size_t, c_unsigned_long_long 360 | implicit none 361 | type(*), intent(inout) :: src 362 | integer(kind=c_size_t), intent(in), value :: src_size 363 | integer(kind=c_unsigned_long_long) :: zstd_find_decompressed_size 364 | end function zstd_find_decompressed_size 365 | 366 | ! size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize) 367 | function zstd_find_frame_compressed_size(src, src_size) bind(c, name='ZSTD_findFrameCompressedSize') 368 | import :: c_size_t 369 | implicit none 370 | type(*), intent(inout) :: src 371 | integer(kind=c_size_t), intent(in), value :: src_size 372 | integer(kind=c_size_t) :: zstd_find_frame_compressed_size 373 | end function zstd_find_frame_compressed_size 374 | 375 | ! size_t ZSTD_flushStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output) 376 | function zstd_flush_stream(zcs, output) bind(c, name='ZSTD_flushStream') 377 | !! Deprecated. 378 | import :: c_ptr, c_size_t, zstd_out_buffer_type 379 | implicit none 380 | type(c_ptr), intent(in), value :: zcs 381 | type(zstd_out_buffer_type), intent(inout) :: output 382 | integer(kind=c_size_t) :: zstd_flush_stream 383 | end function zstd_flush_stream 384 | 385 | ! size_t ZSTD_freeCCtx(ZSTD_CCtx *cctx) 386 | function zstd_free_c_ctx_(c_ctx) bind(c, name='ZSTD_freeCCtx') 387 | import :: c_ptr, c_size_t 388 | implicit none 389 | type(c_ptr), intent(in), value :: c_ctx 390 | integer(kind=c_size_t) :: zstd_free_c_ctx_ 391 | end function zstd_free_c_ctx_ 392 | 393 | ! size_t ZSTD_freeCStream(ZSTD_CStream *zcs) 394 | function zstd_free_c_stream_(zcs) bind(c, name='ZSTD_freeCStream') 395 | import :: c_ptr, c_size_t 396 | implicit none 397 | type(c_ptr), intent(in), value :: zcs 398 | integer(kind=c_size_t) :: zstd_free_c_stream_ 399 | end function zstd_free_c_stream_ 400 | 401 | ! size_t ZSTD_freeDCtx(ZSTD_DCtx *dctx) 402 | function zstd_free_d_ctx_(d_ctx) bind(c, name='ZSTD_freeDCtx') 403 | import :: c_ptr, c_size_t 404 | implicit none 405 | type(c_ptr), intent(in), value :: d_ctx 406 | integer(kind=c_size_t) :: zstd_free_d_ctx_ 407 | end function zstd_free_d_ctx_ 408 | 409 | ! size_t ZSTD_freeDStream(ZSTD_DStream *zds) 410 | function zstd_free_d_stream_(zds) bind(c, name='ZSTD_freeDStream') 411 | import :: c_ptr, c_size_t 412 | implicit none 413 | type(c_ptr), intent(in), value :: zds 414 | integer(kind=c_size_t) :: zstd_free_d_stream_ 415 | end function zstd_free_d_stream_ 416 | 417 | ! unsigned long long ZSTD_getDecompressedSize(const void *src, size_t srcSize) 418 | function zstd_get_decompressed_size(src, src_size) bind(c, name='ZSTD_getDecompressedSize') 419 | !! Deprecated. 420 | import :: c_size_t, c_unsigned_long_long 421 | implicit none 422 | type(*), intent(inout) :: src 423 | integer(kind=c_size_t), intent(in), value :: src_size 424 | integer(kind=c_unsigned_long_long) :: zstd_get_decompressed_size 425 | end function zstd_get_decompressed_size 426 | 427 | ! const char *ZSTD_getErrorName(size_t code) 428 | function zstd_get_error_name_(code) bind(c, name='ZSTD_getErrorName') 429 | import :: c_ptr, c_size_t 430 | implicit none 431 | integer(kind=c_size_t), intent(in), value :: code 432 | type(c_ptr) :: zstd_get_error_name_ 433 | end function zstd_get_error_name_ 434 | 435 | ! unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize) 436 | function zstd_get_frame_content_size(src, src_size) bind(c, name='ZSTD_getFrameContentSize') 437 | !! Deprecated. 438 | import :: c_size_t, c_unsigned_long_long 439 | implicit none 440 | type(*), intent(inout) :: src 441 | integer(kind=c_size_t), intent(in), value :: src_size 442 | integer(kind=c_unsigned_long_long) :: zstd_get_frame_content_size 443 | end function zstd_get_frame_content_size 444 | 445 | ! size_t ZSTD_initCStream(ZSTD_CStream *zcs, int compressionLevel) 446 | function zstd_init_c_stream(zcs, compression_level) bind(c, name='ZSTD_initCStream') 447 | !! Deprecated. 448 | import :: c_int, c_ptr, c_size_t 449 | implicit none 450 | type(c_ptr), intent(in), value :: zcs 451 | integer(kind=c_int), intent(in), value :: compression_level 452 | integer(kind=c_size_t) :: zstd_init_c_stream 453 | end function zstd_init_c_stream 454 | 455 | ! size_t ZSTD_initDStream(ZSTD_DStream *zds) 456 | function zstd_init_d_stream(zds) bind(c, name='ZSTD_initDStream') 457 | import :: c_ptr, c_size_t 458 | implicit none 459 | type(c_ptr), intent(in), value :: zds 460 | integer(kind=c_size_t) :: zstd_init_d_stream 461 | end function zstd_init_d_stream 462 | 463 | ! unsigned ZSTD_isError(size_t code) 464 | function zstd_is_error_(code) bind(c, name='ZSTD_isError') 465 | import :: c_size_t, c_unsigned 466 | implicit none 467 | integer(kind=c_size_t), intent(in), value :: code 468 | integer(kind=c_unsigned) :: zstd_is_error_ 469 | end function zstd_is_error_ 470 | 471 | ! int ZSTD_maxCLevel(void) 472 | function zstd_max_c_level() bind(c, name='ZSTD_maxCLevel') 473 | import :: c_int 474 | implicit none 475 | integer(kind=c_int) :: zstd_max_c_level 476 | end function zstd_max_c_level 477 | 478 | ! int ZSTD_minCLevel(void) 479 | function zstd_min_c_level() bind(c, name='ZSTD_minCLevel') 480 | import :: c_int 481 | implicit none 482 | integer(kind=c_int) :: zstd_min_c_level 483 | end function zstd_min_c_level 484 | 485 | ! unsigned ZSTD_versionNumber(void) 486 | function zstd_version_number() bind(c, name='ZSTD_versionNumber') 487 | import :: c_unsigned 488 | implicit none 489 | integer(kind=c_unsigned) :: zstd_version_number 490 | end function zstd_version_number 491 | 492 | ! const char *ZSTD_versionString(void) 493 | function zstd_version_string_() bind(c, name='ZSTD_versionString') 494 | import :: c_ptr 495 | implicit none 496 | type(c_ptr) :: zstd_version_string_ 497 | end function zstd_version_string_ 498 | end interface 499 | 500 | public :: zstd_c_ctx_reset 501 | public :: zstd_c_ctx_set_parameter 502 | public :: zstd_c_ctx_set_pledged_src_size 503 | public :: zstd_c_param_get_bounds 504 | public :: zstd_c_stream_in_size 505 | public :: zstd_c_stream_out_size 506 | public :: zstd_compress 507 | public :: zstd_compress2 508 | public :: zstd_compress_bound 509 | public :: zstd_compress_c_ctx 510 | public :: zstd_compress_stream 511 | public :: zstd_compress_stream2 512 | public :: zstd_create_c_ctx 513 | public :: zstd_create_c_stream 514 | public :: zstd_create_d_ctx 515 | public :: zstd_create_d_stream 516 | public :: zstd_d_ctx_reset 517 | public :: zstd_d_ctx_set_parameter 518 | public :: zstd_d_stream_in_size 519 | public :: zstd_d_stream_out_size 520 | public :: zstd_decompress 521 | public :: zstd_decompress_bound 522 | public :: zstd_decompress_d_ctx 523 | public :: zstd_decompress_stream 524 | public :: zstd_default_c_level 525 | public :: zstd_d_param_get_bounds 526 | public :: zstd_end_stream 527 | public :: zstd_find_decompressed_size 528 | public :: zstd_find_frame_compressed_size 529 | public :: zstd_flush_stream 530 | public :: zstd_free_c_ctx 531 | public :: zstd_free_c_ctx_ 532 | public :: zstd_free_c_stream 533 | public :: zstd_free_c_stream_ 534 | public :: zstd_free_d_ctx 535 | public :: zstd_free_d_ctx_ 536 | public :: zstd_free_d_stream 537 | public :: zstd_free_d_stream_ 538 | public :: zstd_get_decompressed_size 539 | public :: zstd_get_error_name 540 | public :: zstd_get_error_name_ 541 | public :: zstd_get_frame_content_size 542 | public :: zstd_init_c_stream 543 | public :: zstd_init_d_stream 544 | public :: zstd_is_error 545 | public :: zstd_is_error_ 546 | public :: zstd_max_c_level 547 | public :: zstd_min_c_level 548 | public :: zstd_version_number 549 | public :: zstd_version_string 550 | public :: zstd_version_string_ 551 | 552 | private :: c_f_str_ptr 553 | contains 554 | function zstd_free_c_ctx(c_ctx) result(code) 555 | !! Wrapper function that resets C pointer on success. 556 | type(c_ptr), intent(inout) :: c_ctx 557 | integer(kind=c_size_t) :: code 558 | 559 | code = zstd_free_c_ctx_(c_ctx) 560 | if (.not. zstd_is_error(code)) c_ctx = c_null_ptr 561 | end function zstd_free_c_ctx 562 | 563 | function zstd_free_c_stream(zcs) result(code) 564 | !! Wrapper function that resets C pointer on success. 565 | type(c_ptr), intent(inout) :: zcs 566 | integer(kind=c_size_t) :: code 567 | 568 | code = zstd_free_c_stream_(zcs) 569 | if (.not. zstd_is_error(code)) zcs = c_null_ptr 570 | end function zstd_free_c_stream 571 | 572 | function zstd_free_d_ctx(d_ctx) result(code) 573 | !! Wrapper function that resets C pointer on success. 574 | type(c_ptr), intent(inout) :: d_ctx 575 | integer(kind=c_size_t) :: code 576 | 577 | code = zstd_free_d_ctx_(d_ctx) 578 | if (.not. zstd_is_error(code)) d_ctx = c_null_ptr 579 | end function zstd_free_d_ctx 580 | 581 | function zstd_free_d_stream(zds) result(code) 582 | !! Wrapper function that resets C pointer on success. 583 | type(c_ptr), intent(inout) :: zds 584 | integer(kind=c_size_t) :: code 585 | 586 | code = zstd_free_d_stream_(zds) 587 | if (.not. zstd_is_error(code)) zds = c_null_ptr 588 | end function zstd_free_d_stream 589 | 590 | function zstd_get_error_name(code) result(str) 591 | !! Wrapper function that converts C pointer to Fortran string. 592 | integer(kind=c_size_t), intent(in) :: code 593 | character(len=:), allocatable :: str 594 | 595 | type(c_ptr) :: ptr 596 | 597 | ptr = zstd_get_error_name_(code) 598 | call c_f_str_ptr(ptr, str) 599 | end function zstd_get_error_name 600 | 601 | function zstd_is_error(code) result(is_error) 602 | !! Wrapper function that returns logical instead of integer. 603 | integer(kind=c_size_t), intent(in) :: code 604 | logical :: is_error 605 | 606 | is_error = (zstd_is_error_(code) == 1) 607 | end function zstd_is_error 608 | 609 | function zstd_version_string() result(str) 610 | !! Wrapper function that converts C pointer to Fortran string. 611 | character(len=:), allocatable :: str 612 | 613 | type(c_ptr) :: ptr 614 | 615 | ptr = zstd_version_string_() 616 | call c_f_str_ptr(ptr, str) 617 | end function zstd_version_string 618 | 619 | subroutine c_f_str_ptr(c_str, f_str) 620 | !! Copies a C string, passed as a C pointer, to a Fortran string. 621 | type(c_ptr), intent(in) :: c_str 622 | character(len=:), allocatable, intent(out) :: f_str 623 | 624 | character(kind=c_char), pointer :: ptrs(:) 625 | integer(kind=c_size_t) :: i, sz 626 | 627 | interface 628 | ! size_t strlen(const char *str) 629 | function c_strlen(str) bind(c, name='strlen') 630 | import :: c_ptr, c_size_t 631 | implicit none 632 | type(c_ptr), intent(in), value :: str 633 | integer(kind=c_size_t) :: c_strlen 634 | end function c_strlen 635 | end interface 636 | 637 | copy_if: if (c_associated(c_str)) then 638 | sz = c_strlen(c_str) 639 | if (sz < 0) exit copy_if 640 | call c_f_pointer(c_str, ptrs, [ sz ]) 641 | allocate (character(len=sz) :: f_str) 642 | 643 | do i = 1, sz 644 | f_str(i:i) = ptrs(i) 645 | end do 646 | 647 | return 648 | end if copy_if 649 | 650 | if (.not. allocated(f_str)) f_str = '' 651 | end subroutine c_f_str_ptr 652 | end module zstd 653 | --------------------------------------------------------------------------------