From 36e74c1b57e56a45fbe6713aa5a90e7c0a0f2ae0 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 27 Jun 2023 00:30:45 +1000 Subject: [PATCH] zlib: Add zlib module. This is a replacement for the `zlib` module that used to be built-in and has been replaced by the MicroPython-specific `deflate` module. Also updates the `gzip` module in a similar fashion and provide the `gzip.GzipFile` class and `gzip.open` function. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- python-stdlib/gzip/gzip.py | 50 +++++++++++++++++----------------- python-stdlib/gzip/manifest.py | 2 +- python-stdlib/zlib/manifest.py | 3 ++ python-stdlib/zlib/zlib.py | 39 ++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 26 deletions(-) create mode 100644 python-stdlib/zlib/manifest.py create mode 100644 python-stdlib/zlib/zlib.py diff --git a/python-stdlib/gzip/gzip.py b/python-stdlib/gzip/gzip.py index 6d6c967a..c4473bec 100644 --- a/python-stdlib/gzip/gzip.py +++ b/python-stdlib/gzip/gzip.py @@ -1,29 +1,29 @@ -# import zlib -import uzlib as zlib +# MicroPython gzip module +# MIT license; Copyright (c) 2023 Jim Mussared -FTEXT = 1 -FHCRC = 2 -FEXTRA = 4 -FNAME = 8 -FCOMMENT = 16 +_WBITS = const(15) + +import io, deflate + + +def GzipFile(fileobj): + return deflate.DeflateIO(fileobj, deflate.GZIP, _WBITS) + + +def open(filename, mode): + return deflate.DeflateIO(open(filename, mode), deflate.GZIP, _WBITS, True) + + +if hasattr(deflate.DeflateIO, "write"): + + def compress(data): + f = io.BytesIO() + with GzipFile(fileobj=f) as g: + g.write(data) + return f.getvalue() def decompress(data): - assert data[0] == 0x1F and data[1] == 0x8B - assert data[2] == 8 - flg = data[3] - assert flg & 0xE0 == 0 - i = 10 - if flg & FEXTRA: - i += data[11] << 8 + data[10] + 2 - if flg & FNAME: - while data[i]: - i += 1 - i += 1 - if flg & FCOMMENT: - while data[i]: - i += 1 - i += 1 - if flg & FHCRC: - i += 2 - return zlib.decompress(memoryview(data)[i:], -15) + f = io.BytesIO(data) + with GzipFile(fileobj=f) as g: + return g.read() diff --git a/python-stdlib/gzip/manifest.py b/python-stdlib/gzip/manifest.py index eab70e56..006b538c 100644 --- a/python-stdlib/gzip/manifest.py +++ b/python-stdlib/gzip/manifest.py @@ -1,3 +1,3 @@ -metadata(version="0.1.1") +metadata(version="1.0.0") module("gzip.py") diff --git a/python-stdlib/zlib/manifest.py b/python-stdlib/zlib/manifest.py new file mode 100644 index 00000000..f95602f2 --- /dev/null +++ b/python-stdlib/zlib/manifest.py @@ -0,0 +1,3 @@ +metadata(version="1.0.0", description="Compression and decompression using the deflate algorithm") + +module("zlib.py") diff --git a/python-stdlib/zlib/zlib.py b/python-stdlib/zlib/zlib.py new file mode 100644 index 00000000..e6c342ef --- /dev/null +++ b/python-stdlib/zlib/zlib.py @@ -0,0 +1,39 @@ +# MicroPython zlib module +# MIT license; Copyright (c) 2023 Jim Mussared + +import io, deflate + +_MAX_WBITS = const(15) + + +def _decode_wbits(wbits, decompress): + if -15 <= wbits <= -5: + return ( + deflate.RAW, + -wbits, + ) + elif 5 <= wbits <= 15: + return (deflate.ZLIB, wbits) + elif decompress and wbits == 0: + return (deflate.ZLIB,) + elif 21 <= wbits <= 31: + return (deflate.GZIP, wbits - 16) + elif decompress and 35 <= wbits <= 47: + return (deflate.AUTO, wbits - 32) + else: + raise ValueError("wbits") + + +if hasattr(deflate.DeflateIO, "write"): + + def compress(data, wbits=_MAX_WBITS): + f = io.BytesIO() + with deflate.DeflateIO(f, *_decode_wbits(wbits, False)) as g: + g.write(data) + return f.getvalue() + + +def decompress(data, wbits=_MAX_WBITS): + f = io.BytesIO(data) + with deflate.DeflateIO(f, *_decode_wbits(wbits, True)) as g: + return g.read()