Skip to content

Commit ac852ab

Browse files
authored
Port changes from CodecZlib.jl (#1)
* Port changes from CodecZlib.jl * Fix docstring typo
1 parent d147a6b commit ac852ab

13 files changed

Lines changed: 484 additions & 93 deletions

File tree

.github/dependabot.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
2+
version: 2
3+
updates:
4+
- package-ecosystem: "github-actions"
5+
directory: "/" # Location of package manifests
6+
schedule:
7+
interval: "weekly"

.github/workflows/CI.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: CI
2+
on:
3+
push:
4+
branches:
5+
- master
6+
tags: ['*']
7+
pull_request:
8+
branches:
9+
- master
10+
concurrency:
11+
# Skip intermediate builds: always.
12+
# Cancel intermediate builds: only if it is a pull request build.
13+
group: ${{ github.workflow }}-${{ github.ref }}
14+
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
15+
jobs:
16+
test:
17+
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
18+
runs-on: ${{ matrix.os }}
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
version:
23+
- 'lts'
24+
- '1'
25+
- 'nightly'
26+
os:
27+
- ubuntu-latest
28+
- windows-latest
29+
- macos-latest
30+
arch:
31+
- default
32+
- x86
33+
exclude:
34+
- os: macos-latest
35+
arch: x86
36+
include:
37+
- os: ubuntu-latest
38+
version: 'min'
39+
arch: x64
40+
steps:
41+
- uses: actions/checkout@v6
42+
- uses: julia-actions/setup-julia@v2
43+
with:
44+
version: ${{ matrix.version }}
45+
arch: ${{ matrix.arch }}
46+
show-versioninfo: true
47+
- uses: julia-actions/cache@v3
48+
- uses: julia-actions/julia-buildpkg@v1
49+
- uses: julia-actions/julia-runtest@v1
50+
- uses: julia-actions/julia-processcoverage@v1
51+
- uses: codecov/codecov-action@v6
52+
with:
53+
token: ${{ secrets.CODECOV_TOKEN }}
54+
files: lcov.info

.github/workflows/TagBot.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: TagBot
2+
on:
3+
issue_comment:
4+
types:
5+
- created
6+
workflow_dispatch:
7+
inputs:
8+
lookback:
9+
default: 3
10+
permissions:
11+
actions: read
12+
checks: read
13+
contents: write
14+
deployments: read
15+
issues: read
16+
discussions: read
17+
packages: read
18+
pages: read
19+
pull-requests: read
20+
repository-projects: read
21+
security-events: read
22+
statuses: read
23+
jobs:
24+
TagBot:
25+
if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
26+
runs-on: ubuntu-latest
27+
steps:
28+
- uses: JuliaRegistries/TagBot@v1
29+
with:
30+
token: ${{ secrets.GITHUB_TOKEN }}
31+
# Edit the following line to reflect the actual name of the GitHub Secret containing your private key
32+
ssh: ${{ secrets.DOCUMENTER_KEY }}
33+
# ssh: ${{ secrets.NAME_OF_MY_SSH_PRIVATE_KEY_SECRET }}

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1+
#Mac OS X
2+
*.DS_Store
3+
4+
#VS Code
5+
/.vscode/
6+
17
*.jl.cov
28
*.jl.*.cov
39
*.jl.mem
410
/Manifest.toml
11+
/test/Manifest.toml
512
/.envrc
613
/deps/deps.jl
714
/deps/build.log

Project.toml

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,13 @@ name = "CodecZlibNG"
22
uuid = "642d12eb-acb5-4437-bcfc-a25e07ad685c"
33
license = "MIT"
44
authors = ["Tomas Drvostep <tomas.drvostep@gmail.com>", "Kenta Sato <bicycle1885@gmail.com>"]
5-
version = "0.1.0"
5+
version = "0.2.0-dev"
66

77
[deps]
88
TranscodingStreams = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"
99
ZlibNG_jll = "c62bbaca-5768-5b75-85e2-9a0ea54e1624"
1010

1111
[compat]
12-
TranscodingStreams = "0.9"
12+
TranscodingStreams = "0.9, 0.10, 0.11"
13+
ZlibNG_jll = "2"
1314
julia = "1.6"
14-
15-
[extras]
16-
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
17-
18-
[targets]
19-
test = ["Test"]

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
CodecZlibNG.jl
22
============
3+
4+
[![CI](https://github.com/JuliaIO/CodecZlibNG.jl/actions/workflows/CI.yml/badge.svg)](https://github.com/JuliaIO/CodecZlibNG.jl/actions/workflows/CI.yml)
5+
[![codecov](https://codecov.io/gh/JuliaIO/CodecZlibNG.jl/graph/badge.svg?token=6V3Z847Ywr)](https://codecov.io/gh/JuliaIO/CodecZlibNG.jl)
6+
7+
CodecZlibNG.jl is an experimental alternative to [CodecZlib.jl](https://github.com/JuliaIO/CodecZlib.jl) that wraps the [zlib-ng](https://github.com/zlib-ng/zlib-ng) C library.
8+
39
## Installation
410

511
```julia
@@ -45,4 +51,4 @@ This package exports following codecs and streams:
4551
| `DeflateCompressor` | `DeflateCompressorStream` |
4652
| `DeflateDecompressor` | `DeflateDecompressorStream` |
4753

48-
See docstrings and [TranscodingStreams.jl](https://github.com/bicycle1885/TranscodingStreams.jl) for details.
54+
See docstrings and [TranscodingStreams.jl](https://github.com/JuliaIO/TranscodingStreams.jl) for details.

src/CodecZlibNG.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import TranscodingStreams:
2727
initialize,
2828
finalize,
2929
splitkwargs
30-
using ZlibNG_jll
30+
using ZlibNG_jll: libzng
3131

3232
include("libzng.jl")
3333
include("compression.jl")

src/compression.jl

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,18 @@ Create a gzip compression codec.
2424
2525
Arguments
2626
---------
27-
- `level`: compression level (-1..9)
28-
- `windowbits`: size of history buffer (8..15)
27+
- `level` (-1..9): compression level. 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). -1 requests a default compromise between speed and compression (currently equivalent to level 6).
28+
- `windowbits` (9..15): size of history buffer is `2^windowbits`.
29+
30+
!!! warning
31+
`serialize` and `deepcopy` will not work with this codec due to stored raw pointers.
2932
"""
3033
function GzipCompressor(;level::Integer=Z_DEFAULT_COMPRESSION,
3134
windowbits::Integer=Z_DEFAULT_WINDOWBITS)
3235
if !(-1 level 9)
3336
throw(ArgumentError("compression level must be within -1..9"))
34-
elseif !(8 windowbits 15)
35-
throw(ArgumentError("windowbits must be within 8..15"))
37+
elseif !(9 windowbits 15)
38+
throw(ArgumentError("windowbits must be within 9..15"))
3639
end
3740
# Add 16 to windowBits to write a simple gzip header and trailer around the
3841
# compressed data instead of a zlib wrapper.
@@ -45,6 +48,9 @@ const GzipCompressorStream{S} = TranscodingStream{GzipCompressor,S} where S<:IO
4548
GzipCompressorStream(stream::IO; kwargs...)
4649
4750
Create a gzip compression stream (see `GzipCompressor` for `kwargs`).
51+
52+
!!! warning
53+
`serialize` and `deepcopy` will not work with this stream due to stored raw pointers.
4854
"""
4955
function GzipCompressorStream(stream::IO; kwargs...)
5056
x, y = splitkwargs(kwargs, (:level, :windowbits))
@@ -68,15 +74,18 @@ Create a zlib compression codec.
6874
6975
Arguments
7076
---------
71-
- `level`: compression level (-1..9)
72-
- `windowbits`: size of history buffer (8..15)
77+
- `level` (-1..9): compression level. 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). -1 requests a default compromise between speed and compression (currently equivalent to level 6).
78+
- `windowbits` (9..15): size of history buffer is `2^windowbits`.
79+
80+
!!! warning
81+
`serialize` and `deepcopy` will not work with this codec due to stored raw pointers.
7382
"""
7483
function ZlibCompressor(;level::Integer=Z_DEFAULT_COMPRESSION,
7584
windowbits::Integer=Z_DEFAULT_WINDOWBITS)
7685
if !(-1 level 9)
7786
throw(ArgumentError("compression level must be within -1..9"))
78-
elseif !(8 windowbits 15)
79-
throw(ArgumentError("windowbits must be within 8..15"))
87+
elseif !(9 windowbits 15)
88+
throw(ArgumentError("windowbits must be within 9..15"))
8089
end
8190
return ZlibCompressor(ZNGStream(), level, windowbits)
8291
end
@@ -87,6 +96,9 @@ const ZlibCompressorStream{S} = TranscodingStream{ZlibCompressor,S} where S<:IO
8796
ZlibCompressorStream(stream::IO)
8897
8998
Create a zlib compression stream (see `ZlibCompressor` for `kwargs`).
99+
100+
!!! warning
101+
`serialize` and `deepcopy` will not work with this stream due to stored raw pointers.
90102
"""
91103
function ZlibCompressorStream(stream::IO; kwargs...)
92104
x, y = splitkwargs(kwargs, (:level, :windowbits))
@@ -106,21 +118,24 @@ struct DeflateCompressor <: CompressorCodec
106118
end
107119

108120
"""
109-
DeflateCompressor(;level=$(Z_DEFAULT_COMPRESSION), windowbits=$(Z_DEFAULT_COMPRESSION))
121+
DeflateCompressor(;level=$(Z_DEFAULT_COMPRESSION), windowbits=$(Z_DEFAULT_WINDOWBITS))
110122
111123
Create a deflate compression codec.
112124
113125
Arguments
114126
---------
115-
- `level`: compression level (-1..9)
116-
- `windowbits`: size of history buffer (8..15)
127+
- `level` (-1..9): compression level. 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). -1 requests a default compromise between speed and compression (currently equivalent to level 6).
128+
- `windowbits` (9..15): size of history buffer is `2^windowbits`.
117129
- `memlevel`: memory size used for internal compression state (1..9)
118130
- `strategy`: compression strategy
119131
* 0 <-> Z_DEFAULT_STRATEGY
120132
* 1 <-> Z_FILTERED
121133
* 2 <-> Z_HUFFMAN_ONLY
122134
* 3 <-> Z_RLE
123135
* 4 <-> Z_FIXED
136+
137+
!!! warning
138+
`serialize` and `deepcopy` will not work with this codec due to stored raw pointers.
124139
"""
125140
function DeflateCompressor(;
126141
level::Integer=Z_DEFAULT_COMPRESSION,
@@ -130,8 +145,8 @@ function DeflateCompressor(;
130145
)
131146
if !(-1 level 9)
132147
throw(ArgumentError("compression level must be within -1..9"))
133-
elseif !(8 windowbits 15)
134-
throw(ArgumentError("windowbits must be within 8..15"))
148+
elseif !(9 windowbits 15)
149+
throw(ArgumentError("windowbits must be within 9..15"))
135150
elseif !(1 memlevel 9)
136151
throw(ArgumentError("memlevel must be within 1..9"))
137152
elseif !(0 strategy 4)
@@ -156,14 +171,6 @@ end
156171
# Methods
157172
# -------
158173

159-
function TranscodingStreams.initialize(codec::CompressorCodec)
160-
code = deflate_init!(codec.zstream, codec.level, codec.windowbits)
161-
if code != Z_OK
162-
zerror(codec.zstream, code)
163-
end
164-
return
165-
end
166-
167174
function TranscodingStreams.finalize(codec::CompressorCodec)
168175
zstream = codec.zstream
169176
if zstream.state != C_NULL
@@ -175,31 +182,55 @@ function TranscodingStreams.finalize(codec::CompressorCodec)
175182
return
176183
end
177184

178-
function TranscodingStreams.startproc(codec::CompressorCodec, state::Symbol, error::Error)
179-
code = deflate_reset!(codec.zstream)
180-
if code == Z_OK
181-
return :ok
185+
function TranscodingStreams.startproc(codec::CompressorCodec, state::Symbol, error_ref::Error)
186+
if codec.zstream.state == C_NULL
187+
code = deflate_init!(codec.zstream, codec.level, codec.windowbits)
188+
# errors in deflate_init! do not require clean up, so just throw
189+
if code == Z_OK
190+
return :ok
191+
elseif code == Z_MEM_ERROR
192+
throw(OutOfMemoryError())
193+
elseif code == Z_STREAM_ERROR
194+
error("Z_STREAM_ERROR: invalid parameter, this should be caught in the codec constructor")
195+
elseif code == Z_VERSION_ERROR
196+
error("Z_VERSION_ERROR: zlib library version is incompatible")
197+
else
198+
error("unexpected libzng error code: $(code)")
199+
end
182200
else
183-
error[] = ErrorException(zlib_error_message(codec.zstream, code))
184-
return :error
201+
code = deflate_reset!(codec.zstream)
202+
# errors in deflate_reset! do not require clean up, so just throw
203+
if code == Z_OK
204+
return :ok
205+
elseif code == Z_STREAM_ERROR
206+
error("Z_STREAM_ERROR: the source stream state was inconsistent")
207+
else
208+
error("unexpected libzng error code: $(code)")
209+
end
185210
end
186211
end
187212

188-
function TranscodingStreams.process(codec::CompressorCodec, input::Memory, output::Memory, error::Error)
213+
function TranscodingStreams.process(codec::CompressorCodec, input::Memory, output::Memory, error_ref::Error)
189214
zstream = codec.zstream
215+
if zstream.state == C_NULL
216+
error("startproc must be called before process")
217+
end
190218
zstream.next_in = input.ptr
191-
zstream.avail_in = input.size
219+
avail_in = min(input.size, typemax(UInt32))
220+
zstream.avail_in = avail_in
192221
zstream.next_out = output.ptr
193-
zstream.avail_out = output.size
194-
code = deflate!(zstream, input.size > 0 ? Z_NO_FLUSH : Z_FINISH)
195-
Δin = Int(input.size - zstream.avail_in)
196-
Δout = Int(output.size - zstream.avail_out)
222+
avail_out = min(output.size, typemax(UInt32))
223+
zstream.avail_out = avail_out
224+
code = deflate!(zstream, zstream.avail_in > 0 ? Z_NO_FLUSH : Z_FINISH)
225+
@assert code != Z_STREAM_ERROR # state not clobbered
226+
Δin = Int(avail_in - zstream.avail_in)
227+
Δout = Int(avail_out - zstream.avail_out)
197228
if code == Z_OK
198229
return Δin, Δout, :ok
199230
elseif code == Z_STREAM_END
200231
return Δin, Δout, :end
201232
else
202-
error[] = ErrorException(zlib_error_message(zstream, code))
233+
error_ref[] = ErrorException(zlib_error_message(zstream, code))
203234
return Δin, Δout, :error
204235
end
205236
end

0 commit comments

Comments
 (0)