Skip to content

Commit 61eb682

Browse files
authored
Merge pull request #136 from pycompression/dicts
Fix bugs when setting zdict
2 parents e2abbf2 + afdc22e commit 61eb682

File tree

5 files changed

+94
-29
lines changed

5 files changed

+94
-29
lines changed

CHANGELOG.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Changelog
99
1010
version 1.2.0-dev
1111
-----------------
12+
+ Fix bug where zdict's could not be set for ``isal_zlib.decompressobj`` and
13+
``igzip_lib.IgzipDecompressor``.
1214
+ Escape GIL when calling inflate, deflate, crc32 and adler32 functions to
1315
just like in CPython. This allows for utilising more CPU cores in combination
1416
with the threading module. This comes with a very slight cost in efficiency

src/isal/igzip_libmodule.c

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,32 @@ IgzipDecompressor_dealloc(IgzipDecompressor *self)
4949
Py_TYPE(self)->tp_free((PyObject *)self);
5050
}
5151

52+
53+
static int
54+
set_inflate_zdict_IgzipDecompressor(IgzipDecompressor *self)
55+
{
56+
Py_buffer zdict_buf;
57+
if (PyObject_GetBuffer(self->zdict, &zdict_buf, PyBUF_SIMPLE) == -1) {
58+
return -1;
59+
}
60+
if ((size_t)zdict_buf.len > UINT32_MAX) {
61+
PyErr_SetString(PyExc_OverflowError,
62+
"zdict length does not fit in an unsigned 32-bit integer");
63+
PyBuffer_Release(&zdict_buf);
64+
return -1;
65+
}
66+
int err;
67+
err = isal_inflate_set_dict(&self->state,
68+
zdict_buf.buf, (uint32_t)zdict_buf.len);
69+
PyBuffer_Release(&zdict_buf);
70+
if (err != ISAL_DECOMP_OK) {
71+
isal_inflate_error(err);
72+
return -1;
73+
}
74+
return 0;
75+
}
76+
77+
5278
/* Decompress data of length d->bzs_avail_in_real in d->state.next_in. The output
5379
buffer is allocated dynamically and returned. At most max_length bytes are
5480
returned, so some of the input may not be consumed. d->state.next_in and
@@ -105,12 +131,28 @@ decompress_buf(IgzipDecompressor *self, Py_ssize_t max_length)
105131
err = isal_inflate(&(self->state));
106132
Py_END_ALLOW_THREADS;
107133

108-
if (err != ISAL_DECOMP_OK){
109-
isal_inflate_error(err);
110-
goto error;
134+
switch(err) {
135+
case ISAL_DECOMP_OK:
136+
break;
137+
case ISAL_NEED_DICT:
138+
if (self->zdict != NULL) {
139+
if (set_inflate_zdict_IgzipDecompressor(self) < 0) {
140+
goto error;
141+
}
142+
else
143+
break;
144+
}
145+
else {
146+
isal_inflate_error(err);
147+
goto error;
148+
}
149+
default:
150+
isal_inflate_error(err);
151+
goto error;
111152
}
112-
} while (self->state.avail_out == 0 &&
113-
self->state.block_state != ISAL_BLOCK_FINISH);
153+
154+
} while (self->state.avail_out == 0 || err == ISAL_NEED_DICT);
155+
114156
} while(self->avail_in_real != 0 &&
115157
self->state.block_state != ISAL_BLOCK_FINISH);
116158

@@ -414,7 +456,6 @@ igzip_lib_IgzipDecompressor__new__(PyTypeObject *type,
414456
return NULL;
415457
}
416458
IgzipDecompressor *self = PyObject_New(IgzipDecompressor, type);
417-
int err;
418459
self->eof = 0;
419460
self->needs_input = 1;
420461
self->avail_in_real = 0;
@@ -436,26 +477,10 @@ igzip_lib_IgzipDecompressor__new__(PyTypeObject *type,
436477
self->state.hist_bits = hist_bits;
437478
self->state.crc_flag = flag;
438479
if (self->zdict != NULL){
439-
Py_buffer zdict_buf;
440-
if (PyObject_GetBuffer(self->zdict, &zdict_buf, PyBUF_SIMPLE) == -1) {
441-
Py_CLEAR(self);
442-
return NULL;
443-
}
444-
if ((size_t)zdict_buf.len > UINT32_MAX) {
445-
PyErr_SetString(PyExc_OverflowError,
446-
"zdict length does not fit in an unsigned 32-bits int");
447-
PyBuffer_Release(&zdict_buf);
480+
if (set_inflate_zdict_IgzipDecompressor(self) < 0) {
448481
Py_CLEAR(self);
449482
return NULL;
450483
}
451-
err = isal_inflate_set_dict(&(self->state), zdict_buf.buf,
452-
(uint32_t)zdict_buf.len);
453-
PyBuffer_Release(&zdict_buf);
454-
if (err != ISAL_DECOMP_OK) {
455-
isal_inflate_error(err);
456-
Py_CLEAR(self);
457-
return NULL;
458-
}
459484
}
460485
return (PyObject *)self;
461486
}

src/isal/isal_zlibmodule.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -724,14 +724,28 @@ isal_zlib_Decompress_decompress_impl(decompobject *self, Py_buffer *data,
724724
Py_BEGIN_ALLOW_THREADS
725725
err = isal_inflate(&self->zst);
726726
Py_END_ALLOW_THREADS
727-
728-
if (err != ISAL_DECOMP_OK){
729-
isal_inflate_error(err);
730-
goto abort;
727+
728+
switch(err) {
729+
case ISAL_DECOMP_OK:
730+
break;
731+
case ISAL_NEED_DICT:
732+
if (self->zdict != NULL) {
733+
if (set_inflate_zdict(self) < 0) {
734+
goto abort;
735+
}
736+
else
737+
break;
738+
}
739+
else {
740+
isal_inflate_error(err);
741+
goto abort;
742+
}
743+
default:
744+
isal_inflate_error(err);
745+
goto abort;
731746
}
732747

733-
} while (self->zst.avail_out == 0 &&
734-
self->zst.block_state != ISAL_BLOCK_FINISH);
748+
} while (self->zst.avail_out == 0 || err == ISAL_NEED_DICT);
735749

736750
} while (self->zst.block_state != ISAL_BLOCK_FINISH && ibuflen != 0);
737751

tests/test_compat.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,21 @@ def test_unused_data(unused_size, wbits):
165165
result = decompressor.decompress(compressed + unused_data)
166166
assert result == data
167167
assert decompressor.unused_data == unused_data
168+
169+
170+
def test_zlib_dictionary_decompress():
171+
dictionary = b"bla"
172+
data = b"bladiebla"
173+
compobj = zlib.compressobj(zdict=dictionary)
174+
compressed = compobj.compress(data) + compobj.flush()
175+
decompobj = isal_zlib.decompressobj(zdict=dictionary)
176+
assert decompobj.decompress(compressed) == data
177+
178+
179+
def test_isal_zlib_dictionary_decompress():
180+
dictionary = b"bla"
181+
data = b"bladiebla"
182+
compobj = isal_zlib.compressobj(zdict=dictionary)
183+
compressed = compobj.compress(data) + compobj.flush()
184+
decompobj = zlib.decompressobj(zdict=dictionary)
185+
assert decompobj.decompress(compressed) == data

tests/test_igzip_lib.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,12 @@ def test_failure(self):
224224
with pytest.raises(Exception):
225225
igzd.decompress(self.BAD_DATA * 30)
226226

227+
def test_dictionary(self):
228+
compressor = zlib.compressobj(zdict=b"bla")
229+
data = compressor.compress(b"bladiebla") + compressor.flush()
230+
igzd = IgzipDecompressor(flag=DECOMP_ZLIB, zdict=b"bla")
231+
assert igzd.decompress(data) == b"bladiebla"
232+
227233

228234
@pytest.mark.parametrize("test_offset", range(5))
229235
def test_igzip_decompressor_raw_deflate_unused_data_zlib(test_offset):

0 commit comments

Comments
 (0)