Skip to content

Commit 63a10ff

Browse files
authored
Merge pull request #156 from pycompression/zstandardwindow
Always set the maximum allowed window size for zstandard decompression
2 parents bc9e899 + 4153fa0 commit 63a10ff

File tree

3 files changed

+31
-6
lines changed

3 files changed

+31
-6
lines changed

src/xopen/__init__.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -508,15 +508,26 @@ def _open_zst(
508508
assert compresslevel != 0
509509
if compresslevel is None:
510510
compresslevel = XOPEN_DEFAULT_ZST_COMPRESSION
511+
if zstandard:
512+
max_window_bits = zstandard.WINDOWLOG_MAX
513+
else:
514+
max_window_bits = 31
511515
if threads != 0:
512516
try:
513517
# zstd can compress using multiple cores
518+
program_args: Tuple[str, ...] = ("zstd",)
519+
if "r" in mode:
520+
# Only use --long=31 for decompression. Using it for
521+
# compression overrides level settings for window size and
522+
# forces other zstd users to use `--long=31` to decompress any
523+
# archive that has been compressed by xopen.
524+
program_args += (f"--long={max_window_bits}",)
514525
return _PipedCompressionProgram(
515526
filename,
516527
mode,
517528
compresslevel,
518529
threads,
519-
_PROGRAM_SETTINGS["zstd"],
530+
_ProgramSettings(program_args, tuple(range(1, 20)), "-T"),
520531
)
521532
except OSError:
522533
if zstandard is None:
@@ -525,11 +536,9 @@ def _open_zst(
525536

526537
if zstandard is None:
527538
raise ImportError("zstandard module (python-zstandard) not available")
528-
if compresslevel is not None and "r" not in mode:
529-
cctx = zstandard.ZstdCompressor(level=compresslevel)
530-
else:
531-
cctx = None
532-
f = zstandard.open(filename, mode, cctx=cctx) # type: ignore
539+
dctx = zstandard.ZstdDecompressor(max_window_size=2**max_window_bits)
540+
cctx = zstandard.ZstdCompressor(level=compresslevel)
541+
f = zstandard.open(filename, mode, cctx=cctx, dctx=dctx) # type: ignore
533542
if mode == "rb":
534543
return io.BufferedReader(f)
535544
return io.BufferedWriter(f) # mode "ab" and "wb"

tests/only_zeroes.zst

64.2 KB
Binary file not shown.

tests/test_xopen.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,22 @@ def test_xopen_zst_fails_when_zstandard_not_available(monkeypatch):
576576
f.read()
577577

578578

579+
@pytest.mark.parametrize("threads", (0, 1))
580+
def test_xopen_zst_long_window_size(threads):
581+
if threads == 0 and zstandard is None:
582+
return
583+
elif threads == 1 and not shutil.which("zstd"):
584+
return
585+
# File created with:
586+
# cat /dev/zero | head -c 2147483648 > only_zeroes
587+
# Then compressed with
588+
# zstd --long=31 -19 only_zeroes
589+
test_zst = Path(__file__).parent / "only_zeroes.zst"
590+
with xopen(test_zst, "rb", threads=threads) as f:
591+
data = f.read(1024)
592+
assert data == bytes(1024)
593+
594+
579595
@pytest.mark.parametrize("threads", (0, 1))
580596
@pytest.mark.parametrize("ext", extensions)
581597
def test_pass_file_object_for_reading(ext, threads):

0 commit comments

Comments
 (0)