Skip to content

Commit 8e1c854

Browse files
authored
Merge pull request #50 from pycompression/codesimplification
Simplify code in gzip_ng.py
2 parents 017f748 + e918f3e commit 8e1c854

File tree

2 files changed

+13
-37
lines changed

2 files changed

+13
-37
lines changed

CHANGELOG.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ version 0.5.0-dev
1212
+ Wheels are now build for MacOS arm64 architectures.
1313
+ Fix a bug where READ and WRITE in zlib_ng.gzip_ng were inconsistent with the
1414
values in gzip on Python 3.13
15+
+ Small simplifications to the ``gzip_ng.compress`` and ``gzip_ng.decompress``
16+
functions, which should lead to less overhead.
1517

1618
version 0.4.3
1719
-----------------

src/zlib_ng/gzip_ng.py

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import gzip
2323
import io
2424
import os
25+
import shutil
2526
import struct
2627
import sys
2728
import time
@@ -180,50 +181,27 @@ def write(self, data):
180181
_GzipNGReader = _GzipReader
181182

182183

183-
def _create_simple_gzip_header(compresslevel: int,
184-
mtime=None) -> bytes:
185-
"""
186-
Write a simple gzip header with no extra fields.
187-
:param compresslevel: Compresslevel used to determine the xfl bytes.
188-
:param mtime: The mtime (must support conversion to a 32-bit integer).
189-
:return: A bytes object representing the gzip header.
190-
"""
191-
if mtime is None:
192-
mtime = time.time()
193-
if compresslevel == _COMPRESS_LEVEL_BEST:
194-
xfl = 2
195-
elif compresslevel == _COMPRESS_LEVEL_FAST:
196-
xfl = 4
197-
else:
198-
xfl = 0
199-
# Pack ID1 and ID2 magic bytes, method (8=deflate), header flags (no extra
200-
# fields added to header), mtime, xfl and os (255 for unknown OS).
201-
return struct.pack("<BBBBLBB", 0x1f, 0x8b, 8, 0, int(mtime), xfl, 255)
202-
203-
204184
def compress(data, compresslevel=_COMPRESS_LEVEL_BEST, *, mtime=None):
205185
"""Compress data in one shot and return the compressed string.
206186
compresslevel sets the compression level in range of 0-9.
207187
mtime can be used to set the modification time. The modification time is
208188
set to the current time by default.
209189
"""
210-
if mtime == 0:
211-
# Use zlib as it creates the header with 0 mtime by default.
212-
# This is faster and with less overhead.
213-
return zlib_ng.compress(data, level=compresslevel, wbits=31)
214-
header = _create_simple_gzip_header(compresslevel, mtime)
215-
trailer = struct.pack("<LL", zlib_ng.crc32(data), (len(data) & 0xffffffff))
216-
# Wbits=-15 creates a raw deflate block.
217-
return (header + zlib_ng.compress(data, level=compresslevel, wbits=-15) +
218-
trailer)
190+
# Wbits=31 automatically includes a gzip header and trailer.
191+
gzip_data = zlib_ng.compress(data, level=compresslevel, wbits=31)
192+
if mtime is None:
193+
mtime = time.time()
194+
# Reuse gzip header created by zlib_ng, replace mtime and OS byte for
195+
# consistency.
196+
header = struct.pack("<4sLBB", gzip_data, int(mtime), gzip_data[8], 255)
197+
return header + gzip_data[10:]
219198

220199

221200
def decompress(data):
222201
"""Decompress a gzip compressed string in one shot.
223202
Return the decompressed string.
224203
"""
225-
fp = io.BytesIO(data)
226-
reader = _GzipReader(fp, max(len(data), 16))
204+
reader = _GzipReader(data)
227205
return reader.readall()
228206

229207

@@ -325,11 +303,7 @@ def main():
325303
global READ_BUFFER_SIZE
326304
READ_BUFFER_SIZE = args.buffer_size
327305
try:
328-
while True:
329-
block = in_file.read(args.buffer_size)
330-
if block == b"":
331-
break
332-
out_file.write(block)
306+
shutil.copyfileobj(in_file, out_file, args.buffer_size)
333307
finally:
334308
if in_file is not sys.stdin.buffer:
335309
in_file.close()

0 commit comments

Comments
 (0)