Skip to content

Commit d351209

Browse files
Merge pull request #229 from sergey-dryabzhinsky/Issue-228-try-to-decompress-streamed-data
Issue 228 try to decompress streamed data
2 parents a51aab9 + dffcfcb commit d351209

File tree

8 files changed

+94
-59
lines changed

8 files changed

+94
-59
lines changed

.github/workflows/Build_wheels_for_cpython27_x86.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
matrix: linux
2020
arch: i386
2121
tag_arch: i686
22-
release: bionic
22+
release: bionic
2323
mirror: http://azure.archive.ubuntu.com/ubuntu
2424
#version: 1.5.6.7
2525
#pyver: "2.7"
@@ -63,11 +63,11 @@ jobs:
6363
sudo mount none ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}}/proc -t proc
6464
sudo mount none ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}}/dev/pts -t devpts
6565
sudo mount none ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}}/sys -t sysfs
66-
echo " deb [trusted=yes] http://packages.rusoft.ru/ppa/rusoft/python ubuntu-${{matrix.os.release}} main" > rusoft-python.list
67-
echo " deb [trusted=yes] http://packages.rusoft.ru/ppa/rusoft/backports ubuntu-${{matrix.os.release}} main" > rusoft-backports.list
68-
echo " deb [trusted=yes] http://packages.rusoft.ru/ppa/rusoft/packages ubuntu-${{matrix.os.release}} main" > rusoft-packages.list
69-
echo " deb [trusted=yes] http://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu ${{matrix.os.release}} main" > deadsnakes.list
70-
echo "# deb [trusted=yes] http://apt.llvm.org/${{matrix.os.release}}/ llvm-toolchain-${{matrix.os.release}}-18 main " > clang.list
66+
echo "# deb [trusted=yes] http://packages.rusoft.ru/ppa/rusoft/python ubuntu-${{matrix.os.release}} main" > rusoft-python.list
67+
echo "# deb [trusted=yes] http://packages.rusoft.ru/ppa/rusoft/backports ubuntu-${{matrix.os.release}} main" > rusoft-backports.list
68+
echo "# deb [trusted=yes] http://packages.rusoft.ru/ppa/rusoft/packages ubuntu-${{matrix.os.release}} main" > rusoft-packages.list
69+
echo "# deb [trusted=yes] http://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu ${{matrix.os.release}} main" > deadsnakes.list
70+
echo "# deb [trusted=yes] http://apt.llvm.org/${{matrix.os.release}}/ llvm-toolchain-${{matrix.os.release}}-20 main " > clang.list
7171
7272
false && sudo find ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} -iname apt
7373
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /usr/bin/apt update
@@ -93,7 +93,7 @@ jobs:
9393
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /usr/bin/apt-cache madison clang-18
9494
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /usr/bin/apt install -y ${{matrix.os.pypkg}}-dev gcc pkg-config ${{matrix.os.pypkgadd}}
9595
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /bin/bash -c "wget ${{matrix.os.getpipurl}} -O get-pip.py && ${{matrix.os.pypkg}} get-pip.py"
96-
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /bin/bash -c "${{matrix.os.pypkg}} -m pip install -U 'setuptools<72.0'"
96+
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /bin/bash -c "${{matrix.os.pypkg}} -m pip install -U 'setuptools'"
9797
9898
- name: Pepare source and build wheel for ${{matrix.os.pypkg}} ${{matrix.os.arch}}
9999
if: matrix.os.matrix == 'linux'
@@ -108,8 +108,8 @@ jobs:
108108
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} echo GCC
109109
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} gcc -v
110110
false && sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} echo CLANG
111-
false && dead sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} clang-18 -v
112-
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /bin/bash -c "cd /build_wheel/zstd-$version && ZSTD_ASM=1 ZSTD_WARNINGS=1 _ZSTD_WERRORS=1 _ZSTD_SMALL=1 _ZSTD_ASM_BMI2=1 ZSTD_THREADS=1 _ZSTD_EXTERNAL=1 ${{matrix.os.pypkg}} setup.py bdist_wheel "
111+
false && sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} clang-20 -v
112+
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /bin/bash -c "cd /build_wheel/zstd-$version && _CC=clang-20 ZSTD_ASM=1 ZSTD_WARNINGS=1 _ZSTD_WERRORS=1 _ZSTD_SMALL=1 _ZSTD_ASM_BMI2=1 ZSTD_THREADS=1 _ZSTD_EXTERNAL=1 ${{matrix.os.pypkg}} setup.py bdist_wheel "
113113
114114
- name: Test wheel for ${{matrix.os.pypkg}} ${{matrix.os.arch}}
115115
if: matrix.os.matrix == 'linux'

.github/workflows/Build_wheels_for_cpython27_x86_64.yml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Build wheels for CPython2.7 x64 on Ubuntu18 with GCC-7 with All warnings
1+
name: Build wheels for CPython2.7 x64 on Ubuntu16 with GCC-14 with All warnings
22

33
on: [push, pull_request]
44

@@ -19,7 +19,7 @@ jobs:
1919
matrix: linux
2020
arch: amd64
2121
tag_arch: x86_64
22-
release: bionic
22+
release: xenial
2323
mirror: http://azure.archive.ubuntu.com/ubuntu
2424
#version: 1.5.6.7
2525
#pyver: "2.7"
@@ -66,6 +66,7 @@ jobs:
6666
echo " deb [trusted=yes] http://packages.rusoft.ru/ppa/rusoft/python ubuntu-${{matrix.os.release}} main" > rusoft-python.list
6767
echo " deb [trusted=yes] http://packages.rusoft.ru/ppa/rusoft/backports ubuntu-${{matrix.os.release}} main" > rusoft-backports.list
6868
echo " deb [trusted=yes] http://packages.rusoft.ru/ppa/rusoft/packages ubuntu-${{matrix.os.release}} main" > rusoft-packages.list
69+
echo " deb [trusted=yes] http://packages.rusoft.ru/ppa/rusoft/toolchain ubuntu-${{matrix.os.release}} main" > rusoft-toolchain.list
6970
echo "# deb [trusted=yes] http://apt.llvm.org/${{matrix.os.release}}/ llvm-toolchain-${{matrix.os.release}}-16 main " > clang.list
7071
echo "# deb [trusted=yes] http://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu ${{matrix.os.release}} main" > deadsnakes.list
7172
false && sudo find ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} -iname apt
@@ -89,9 +90,9 @@ jobs:
8990
- name: Pepare for ${{matrix.os.pypkg}} ${{matrix.os.arch}}
9091
if: matrix.os.matrix == 'linux'
9192
run: |
92-
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /usr/bin/apt install -y ${{matrix.os.pypkg}}-dev gcc pkg-config ${{matrix.os.pypkgadd}}
93+
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /usr/bin/apt install -y ${{matrix.os.pypkg}}-dev gcc-14 pkg-config ${{matrix.os.pypkgadd}}
9394
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /bin/bash -c "wget ${{matrix.os.getpipurl}} -O get-pip.py && ${{matrix.os.pypkg}} get-pip.py || true"
94-
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /bin/bash -c "${{matrix.os.pypkg}} -m pip install -U 'setuptools<72.0'"
95+
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /bin/bash -c "${{matrix.os.pypkg}} -m pip install -U 'setuptools'"
9596
9697
- name: Pepare source and build wheel for ${{matrix.os.pypkg}} ${{matrix.os.arch}}
9798
if: matrix.os.matrix == 'linux'
@@ -101,9 +102,9 @@ jobs:
101102
sudo tar -xvf dist/zstd-$version.tar.gz -C ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}}/build_wheel/
102103
false && sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} env
103104
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} pkg-config libzstd --modversion
104-
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} echo GCC-7
105-
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} gcc -v
106-
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /bin/bash -c "cd /build_wheel/zstd-$version && ZSTD_ASM=1 _ZSTD_SMALL=1 ZSTD_WARNINGS=1 _ZSTD_WERRORS=1 _ZSTD_ASM_BMI2=1 ZSTD_THREADS=1 _ZSTD_EXTERNAL=1 ${{matrix.os.pypkg}} setup.py bdist_wheel"
105+
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} echo GCC-14
106+
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} gcc-14 -v
107+
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /bin/bash -c "cd /build_wheel/zstd-$version && CC=gcc-14 ZSTD_ASM=1 _ZSTD_SMALL=1 ZSTD_WARNINGS=1 _ZSTD_WERRORS=1 _ZSTD_ASM_BMI2=1 ZSTD_THREADS=1 _ZSTD_EXTERNAL=1 ${{matrix.os.pypkg}} setup.py bdist_wheel"
107108
108109
- name: Test wheel for ${{matrix.os.pypkg}} ${{matrix.os.arch}}
109110
if: matrix.os.matrix == 'linux'

.github/workflows/Build_wheels_for_cpython34_x86_64.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ jobs:
106106
run: |
107107
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} find /build_wheel/
108108
sudo cp -v glibc-check.sh ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}}/build_wheel/zstd-${{matrix.os.version}}/
109-
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /bin/bash -c "cd /build_wheel/zstd-${{matrix.os.version}}/ ls -lh build/*/zstd.*so; ldd build/*/zstd.*so ; file build/*/zstd.*.so; bash ./glibc-check.sh build/*/zstd.*so"
109+
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /bin/bash -c "cd /build_wheel/zstd-${{matrix.os.version}}/ && ls -lh build/*/zstd.*so; ldd build/*/zstd.*so ; file build/*/zstd.*.so; bash ./glibc-check.sh build/*/zstd.*so"
110110
sudo chroot ./ubuntu-${{matrix.os.release}}-${{matrix.os.arch}} /bin/bash -c "cd /build_wheel/zstd-${{matrix.os.version}} && ${{matrix.os.pypkg}} setup.py test"
111111
112112
- name: Pepare wheel for upload

README.rst

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
python-zstd
33
=============
44

5-
.. |releaseW| image:: https://github.com/sergey-dryabzhinsky/python-zstd/actions/workflows/build-wheels.yml/badge.svg?tag=v1.5.6.7
5+
.. |releaseW| image:: https://github.com/sergey-dryabzhinsky/python-zstd/actions/workflows/build-wheels.yml/badge.svg?tag=v1.5.6.8
66
:target: https://github.com/sergey-dryabzhinsky/python-zstd/actions/workflows/build-wheels.yml
77

88
.. |masterW| image:: https://github.com/sergey-dryabzhinsky/python-zstd/actions/workflows/build-wheels.yml/badge.svg
@@ -127,7 +127,7 @@ python-zstd
127127
| cpython 3.14 x64 u24 | |cpython314x64u20| |
128128
+----------------------+---------------------+
129129
| Release | |releaseW| |
130-
| 1.5.6.7 | |
130+
| 1.5.6.8 | |
131131
+----------------------+---------------------+
132132
| Master | |masterW| |
133133
+----------------------+---------------------+
@@ -328,6 +328,8 @@ ZSTD_uncompress (data): string|bytes
328328

329329
Support compressed data with multiple/concatenated frames (blocks) (since 1.5.5.1).
330330

331+
Support streamed data, since 1.5.6.8.
332+
331333
Params:
332334

333335
* **data**: string|bytes - input compressed data block, length limited by 2Gb by Python API
@@ -341,19 +343,19 @@ ZSTD_uncompress (data): string|bytes
341343
Since: 0.1
342344

343345
ZSTD_check (data): int
344-
Function, checks if input is zstd compressed data block, returns 1 if yes, 0 if no.
346+
Function, checks if input is zstd compressed data block, and returns: 1 if yes, 0 if no or 2 if it is a stream data.
345347

346-
Support compressed data with multiple/concatenated frames (blocks) .
348+
Support compressed data with multiple/concatenated frames (blocks) .
347349

348-
Params:
350+
Params:
349351

350-
* **data**: string|bytes - input compressed data block, length limited by 2Gb by Python API
352+
* **data**: string|bytes - input compressed data block, length limited by 2Gb by Python API
351353

352-
Aliases:
354+
Aliases:
353355
- *check(...)*,
354356
- *verify(...)* since: 1.5.6.3
355357

356-
Since: 1.5.6.2
358+
Since: 1.5.6.2
357359

358360
version (): string|bytes
359361
Returns this module doted version string.

src/python-zstd.c

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,8 @@ static PyObject *py_zstd_uncompress(PyObject* self, PyObject *args)
154154
const char *source, *src;
155155
Py_ssize_t source_size, ss, seek_frame;
156156
uint64_t dest_size, frame_size;
157-
char error = 0;
158-
size_t cSize;
157+
char error = 0, streamed = 0;
158+
size_t cSize = 0, processed = 0;
159159

160160
#if PY_MAJOR_VERSION >= 3
161161
if (!PyArg_ParseTuple(args, "y#", &source, &source_size))
@@ -166,10 +166,15 @@ static PyObject *py_zstd_uncompress(PyObject* self, PyObject *args)
166166
#endif
167167

168168
dest_size = (uint64_t) ZSTD_getFrameContentSize(source, source_size);
169-
if (dest_size == ZSTD_CONTENTSIZE_UNKNOWN || dest_size == ZSTD_CONTENTSIZE_ERROR) {
169+
if (dest_size == ZSTD_CONTENTSIZE_ERROR) {
170170
PyErr_Format(ZstdError, "Input data invalid or missing content size in frame header.");
171171
return NULL;
172-
}
172+
} else if (dest_size == ZSTD_CONTENTSIZE_UNKNOWN) {
173+
// probably streamed data
174+
streamed = 1;
175+
dest_size = ZSTD_DStreamOutSize();
176+
} else {
177+
// known block
173178

174179
// Find real dest_size across multiple frames
175180
ss = source_size;
@@ -185,15 +190,37 @@ static PyObject *py_zstd_uncompress(PyObject* self, PyObject *args)
185190
if (ZSTD_isError(frame_size)) break;
186191
dest_size += frame_size;
187192
}
188-
193+
}
189194
result = PyBytes_FromStringAndSize(NULL, dest_size);
190195

191196
if (result != NULL) {
192197
char *dest = PyBytes_AS_STRING(result);
193198

194199
Py_BEGIN_ALLOW_THREADS
195-
// get real dest_size
196-
cSize = ZSTD_decompress(dest, dest_size, source, source_size);
200+
if (streamed) {
201+
ZSTD_DStream* zds;
202+
zds = ZSTD_createDStream();
203+
// buffers create and decompress
204+
ZSTD_initDStream(zds);
205+
ZSTD_outBuffer out;
206+
ZSTD_inBuffer in;
207+
in.src = source;
208+
in.pos = 0;
209+
in.size = source_size;
210+
out.dst = dest;
211+
out.pos = 0;
212+
out.size = dest_size;
213+
processed = ZSTD_decompressStream(zds, &out, &in);
214+
if (processed==0) {
215+
cSize=out.pos;
216+
if (cSize) dest_size=cSize;
217+
}
218+
ZSTD_freeDStream(zds);
219+
}
220+
else {
221+
cSize = ZSTD_decompress(dest, dest_size, source, source_size);
222+
}
223+
197224
Py_END_ALLOW_THREADS
198225

199226
if (ZSTD_isError(cSize)) {
@@ -240,9 +267,9 @@ static PyObject *py_zstd_check(PyObject* self, PyObject *args)
240267
{
241268
UNUSED(self);
242269
//PyObject *result;
243-
const char *source, *src;
244-
Py_ssize_t source_size, ss, seek_frame;
245-
uint64_t dest_size, frame_size, error=0;
270+
const char *source;
271+
Py_ssize_t source_size;
272+
uint64_t dest_size/* ,error=0*/;
246273
//char error = 0;
247274
//size_t cSize;
248275

@@ -255,29 +282,15 @@ static PyObject *py_zstd_check(PyObject* self, PyObject *args)
255282
#endif
256283

257284
dest_size = (uint64_t) ZSTD_getFrameContentSize(source, source_size);
258-
if (dest_size == ZSTD_CONTENTSIZE_UNKNOWN || dest_size == ZSTD_CONTENTSIZE_ERROR) {
285+
if (dest_size == ZSTD_CONTENTSIZE_ERROR) {
259286
//PyErr_Format(ZstdError, "Input data invalid or missing content size in frame header.");
260287
return Py_BuildValue("i", 0);
261-
} else {
262-
263-
// Find real dest_size across multiple frames
264-
ss = source_size;
265-
seek_frame = ss - 1;
266-
src = source;
267-
while (seek_frame < ss) {
268-
seek_frame = ZSTD_findFrameCompressedSize(src, ss);
269-
if (ZSTD_isError(seek_frame)) { error=1; break;}
270-
src += seek_frame;
271-
ss -= seek_frame;
272-
if (ss <=0) break;
273-
frame_size = (uint64_t) ZSTD_getFrameContentSize(src, ss);
274-
if (ZSTD_isError(frame_size)) { error=1; break;}
275-
dest_size += frame_size;
276-
}
288+
} else if (dest_size == ZSTD_CONTENTSIZE_UNKNOWN) {
289+
// content valid, just streamed
290+
//dest_size =/* ZSTD_BLOCKSIZE_MAX;*/ ZSTD_DStreamOutSize();
291+
return Py_BuildValue("i", 2);
277292
}
278-
if (error) return Py_BuildValue("i", -1);
279-
/*if (ss<=0)
280-
return Py_BuildValue("i", 0);*/
293+
//if (error) return Py_BuildValue("i", -1);
281294
return Py_BuildValue("i", 1);
282295
}
283296

tests/test_data/.gitkeep

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hello there

tests/test_data/facebook.ico.zst

1.96 KB
Binary file not shown.

tests/test_decompress.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Tests
22

3-
import sys
4-
from tests.base import BaseTestZSTD, zstd, tDATA, log
3+
import sys, os
4+
from tests.base import BaseTestZSTD, zstd, tDATA, log, raise_skip
55

66
class TestZstdDecompress(BaseTestZSTD):
77

@@ -11,16 +11,34 @@ def test_decompression_null(self):
1111
else:
1212
DATA = b''
1313
self.assertRaises(zstd.Error, zstd.uncompress, zstd.compress(DATA)+b' ')
14+
15+
def test_decompression_streamed(self):
16+
#log.info('cwd: %s' % os.getcwd())
17+
f = open("tests/test_data/facebook.ico.zst","rb")
18+
DATA = f.read()
19+
f.close()
20+
log.info('data check, should be 2: %s' % zstd.check(DATA))
21+
zstd.uncompress(DATA)
22+
#self.assertRaises(zstd.Error, zstd.uncompress, DATA)
1423

24+
def test_decompression_rusted(self):
25+
if sys.hexversion < 0x03000000:
26+
raise_skip("need python version >= 3")
27+
data = b'{}'
28+
cdata = b'\x28\xb5\x2f\xfd\x00\x58\x11\x00\x00\x7b\x7d'
29+
log.info('data check, should be 2: %s' % zstd.check(cdata))
30+
log.info("data must be '{}': %r" % zstd.uncompress(cdata))
31+
self.assertEqual(data, zstd.uncompress(cdata))
32+
1533
def test_check_compressed(self):
1634
cdata = zstd.compress(tDATA)
1735
check = zstd.check(cdata)
18-
log.info("zstd compressed data check (1):%r" % check)
36+
log.info("zstd compressed data check, must be (1):%r" % check)
1937
self.assertEqual(1, check)
2038

2139
def test_check_not_compressed(self):
2240
check = zstd.check(tDATA)
23-
log.info("zstd not compressed data check (0):%r" % check)
41+
log.info("zstd not compressed data check, must be (0):%r" % check)
2442
self.assertEqual(0, check)
2543

2644
def test_check_uncompressed(self):

0 commit comments

Comments
 (0)