|
| 1 | +try: |
| 2 | + # Check if deflate is available. |
| 3 | + import deflate |
| 4 | + import io |
| 5 | +except ImportError: |
| 6 | + print("SKIP") |
| 7 | + raise SystemExit |
| 8 | + |
| 9 | +# zlib.compress(b'micropython hello world hello world micropython', wbits=-9) |
| 10 | +data_raw = b'\xcb\xcdL.\xca/\xa8,\xc9\xc8\xcfS\xc8H\xcd\xc9\xc9W(\xcf/\xcaIAa\xe7"\xd4\x00\x00' |
| 11 | +# zlib.compress(b'micropython hello world hello world micropython', wbits=9) |
| 12 | +data_zlib = b'\x18\x95\xcb\xcdL.\xca/\xa8,\xc9\xc8\xcfS\xc8H\xcd\xc9\xc9W(\xcf/\xcaIAa\xe7"\xd4\x00\x00\xbc\xfa\x12\x91' |
| 13 | +# zlib.compress(b'micropython hello world hello world micropython', wbits=25) |
| 14 | +data_gzip = b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xcb\xcdL.\xca/\xa8,\xc9\xc8\xcfS\xc8H\xcd\xc9\xc9W(\xcf/\xcaIAa\xe7"\xd4\x00\x00"\xeb\xc4\x98/\x00\x00\x00' |
| 15 | + |
| 16 | +# compress(b'hello' + bytearray(300) + b'hello', format=deflate.RAW, 5) |
| 17 | +data_wbits_5 = b"\xcbH\xcd\xc9\xc9g\x18\xe9\x00\x08\x88\x95\xcfH\xcd\xc9\xc9\x07\x00" |
| 18 | +# compress(b'hello' + bytearray(300) + b'hello', format=deflate.RAW, 6) |
| 19 | +data_wbits_6 = b"\xcbH\xcd\xc9\xc9g\x18\xe9\x00\x08\x88\xd5\x9f\x91\x9a\x93\x93\x0f\x00" |
| 20 | +# compress(b'hello' + bytearray(300) + b'hello', format=deflate.RAW, 8) |
| 21 | +data_wbits_8 = b"\xcbH\xcd\xc9\xc9g\x18\xe9\x00\x08\x88\xf5\x7fFjNN>\x00" |
| 22 | +# compress(b'hello' + bytearray(2000) + b'hello', format=deflate.RAW, 10) |
| 23 | +data_wbits_10 = b"\xcbH\xcd\xc9\xc9g\x18\xe9\x00\x08Fz\x18\x00\xc3`\xa4'\x03`2\x18\xe99\x01\x98\x13Fz\xfe\x07\xe6\xff\x91\x9e\xff\x81\xf9\x7f\xa4\xe7\x7f`\xfe\x1f\xba\xf9?#5''\x1f\x00" |
| 24 | + |
| 25 | + |
| 26 | +def decompress(data, *args): |
| 27 | + buf = io.BytesIO(data) |
| 28 | + with deflate.DeflateIO(buf, *args) as g: |
| 29 | + return g.read() |
| 30 | + |
| 31 | + |
| 32 | +def decompress_error(data, *args): |
| 33 | + try: |
| 34 | + decompress(data, *args) |
| 35 | + except OSError: |
| 36 | + print("OSError") |
| 37 | + except EOFError: |
| 38 | + print("EOFError") |
| 39 | + except ValueError: |
| 40 | + print("ValueError") |
| 41 | + |
| 42 | + |
| 43 | +# Basic handling of format and detection. |
| 44 | +print(decompress(data_raw, deflate.RAW)) |
| 45 | +print(decompress(data_zlib, deflate.ZLIB)) |
| 46 | +print(decompress(data_gzip, deflate.GZIP)) |
| 47 | +print(decompress(data_zlib)) # detect zlib/gzip. |
| 48 | +print(decompress(data_gzip)) # detect zlib/gzip. |
| 49 | + |
| 50 | +decompress_error(data_raw) # cannot detect zlib/gzip from raw stream |
| 51 | +decompress_error(data_raw, deflate.ZLIB) |
| 52 | +decompress_error(data_raw, deflate.GZIP) |
| 53 | +decompress_error(data_zlib, deflate.RAW) |
| 54 | +decompress_error(data_zlib, deflate.GZIP) |
| 55 | +decompress_error(data_gzip, deflate.RAW) |
| 56 | +decompress_error(data_gzip, deflate.ZLIB) |
| 57 | + |
| 58 | +# Invalid data stream. |
| 59 | +decompress_error(b"abcef", deflate.RAW) |
| 60 | + |
| 61 | +# Invalid block type. final-block, block-type=3. |
| 62 | +decompress_error(b"\x07", deflate.RAW) |
| 63 | + |
| 64 | +# Truncated stream. |
| 65 | +decompress_error(data_raw[:10], deflate.RAW) |
| 66 | + |
| 67 | +# Partial reads. |
| 68 | +buf = io.BytesIO(data_zlib) |
| 69 | +with deflate.DeflateIO(buf) as g: |
| 70 | + print(buf.seek(0, 1)) # verify stream is not read until first read of the DeflateIO stream. |
| 71 | + print(g.read(1)) |
| 72 | + print(buf.seek(0, 1)) # verify that only the minimal amount is read from the source |
| 73 | + print(g.read(1)) |
| 74 | + print(buf.seek(0, 1)) |
| 75 | + print(g.read(2)) |
| 76 | + print(buf.seek(0, 1)) |
| 77 | + print(g.read()) |
| 78 | + print(buf.seek(0, 1)) |
| 79 | + print(g.read(1)) |
| 80 | + print(buf.seek(0, 1)) |
| 81 | + print(g.read()) |
| 82 | + |
| 83 | +# Invalid zlib checksum (+ length for gzip). Note: only checksum errors are |
| 84 | +# currently detected, see the end of uzlib_uncompress_chksum(). |
| 85 | +decompress_error(data_zlib[:-4] + b"\x00\x00\x00\x00") |
| 86 | +decompress_error(data_gzip[:-8] + b"\x00\x00\x00\x00\x00\x00\x00\x00") |
| 87 | +decompress_error(data_zlib[:-4] + b"\x00\x00\x00\x00", deflate.ZLIB) |
| 88 | +decompress_error(data_gzip[:-8] + b"\x00\x00\x00\x00\x00\x00\x00\x00", deflate.GZIP) |
| 89 | + |
| 90 | +# Reading from a closed underlying stream. |
| 91 | +b = io.BytesIO(data_raw) |
| 92 | +g = deflate.DeflateIO(b, deflate.RAW) |
| 93 | +g.read(4) |
| 94 | +b.close() |
| 95 | +try: |
| 96 | + g.read(4) |
| 97 | +except ValueError: |
| 98 | + print("ValueError") |
| 99 | + |
| 100 | +# Reading from a closed DeflateIO. |
| 101 | +b = io.BytesIO(data_raw) |
| 102 | +g = deflate.DeflateIO(b, deflate.RAW) |
| 103 | +g.read(4) |
| 104 | +g.close() |
| 105 | +try: |
| 106 | + g.read(4) |
| 107 | +except OSError: |
| 108 | + print("OSError") |
| 109 | + |
| 110 | +# Gzip header with extra flags (FCOMMENT FNAME FEXTRA FHCRC) enabled. |
| 111 | +data_gzip_header_extra = b"\x1f\x8b\x08\x1e}\x9a\x9bd\x02\x00\x00\x00\x00\x00\x00\xff\xcb\xcdL.\xca/\xa8,\xc9\xc8\xcf\x03\x00\xf2KF>\x0b\x00\x00\x00" |
| 112 | +print(decompress(data_gzip_header_extra)) |
| 113 | + |
| 114 | +# Test patterns. |
| 115 | +PATTERNS_ZLIB = [ |
| 116 | + # Packed results produced by CPy's zlib.compress() |
| 117 | + (b"0", b"x\x9c3\x00\x00\x001\x001"), |
| 118 | + (b"a", b"x\x9cK\x04\x00\x00b\x00b"), |
| 119 | + (b"0" * 100, b"x\x9c30\xa0=\x00\x00\xb3q\x12\xc1"), |
| 120 | + ( |
| 121 | + bytes(range(64)), |
| 122 | + b"x\x9cc`dbfaec\xe7\xe0\xe4\xe2\xe6\xe1\xe5\xe3\x17\x10\x14\x12\x16\x11\x15\x13\x97\x90\x94\x92\x96\x91\x95\x93WPTRVQUS\xd7\xd0\xd4\xd2\xd6\xd1\xd5\xd370426153\xb7\xb0\xb4\xb2\xb6\xb1\xb5\xb3\x07\x00\xaa\xe0\x07\xe1", |
| 123 | + ), |
| 124 | + (b"hello", b"x\x01\x01\x05\x00\xfa\xffhello\x06,\x02\x15"), # compression level 0 |
| 125 | + # adaptive/dynamic huffman tree |
| 126 | + ( |
| 127 | + b"13371813150|13764518736|12345678901", |
| 128 | + b"x\x9c\x05\xc1\x81\x01\x000\x04\x04\xb1\x95\\\x1f\xcfn\x86o\x82d\x06Qq\xc8\x9d\xc5X}<e\xb5g\x83\x0f\x89X\x07\xab", |
| 129 | + ), |
| 130 | + # dynamic Huffman tree with "case 17" (repeat code for 3-10 times) |
| 131 | + ( |
| 132 | + b">I}\x00\x951D>I}\x00\x951D>I}\x00\x951D>I}\x00\x951D", |
| 133 | + b"x\x9c\x05\xc11\x01\x00\x00\x00\x010\x95\x14py\x84\x12C_\x9bR\x8cV\x8a\xd1J1Z)F\x1fw`\x089", |
| 134 | + ), |
| 135 | +] |
| 136 | +for unpacked, packed in PATTERNS_ZLIB: |
| 137 | + print(decompress(packed) == unpacked) |
| 138 | + print(decompress(packed, deflate.ZLIB) == unpacked) |
| 139 | + |
| 140 | +# Older version's of CPython's zlib module still included the checksum and length (as if it were a zlib/gzip stream). |
| 141 | +# Make sure there're no problem decompressing this. |
| 142 | +data_raw_with_footer = data_raw + b"\x00\x00\x00\x00\x00\x00\x00\x00" |
| 143 | +print(decompress(data_raw_with_footer, deflate.RAW)) |
| 144 | + |
| 145 | +# Valid wbits values. |
| 146 | +decompress_error(data_wbits_5, deflate.RAW, -1) |
| 147 | +print(len(decompress(data_wbits_5, deflate.RAW, 0))) |
| 148 | +decompress_error(data_wbits_5, deflate.RAW, 1) |
| 149 | +decompress_error(data_wbits_5, deflate.RAW, 4) |
| 150 | +for i in range(5, 16): |
| 151 | + print(len(decompress(data_wbits_5, deflate.RAW, i))) |
| 152 | +decompress_error(data_wbits_5, deflate.RAW, 16) |
| 153 | + |
| 154 | +# Invalid values for format. |
| 155 | +decompress_error(data_raw, -1) |
| 156 | +decompress_error(data_raw, 5) |
| 157 | + |
| 158 | +# Data that requires a higher wbits value. |
| 159 | +decompress_error(data_wbits_6, deflate.RAW, 5) |
| 160 | +print(len(decompress(data_wbits_6, deflate.RAW, 6))) |
| 161 | +print(len(decompress(data_wbits_6, deflate.RAW, 7))) |
| 162 | +decompress_error(data_wbits_8, deflate.RAW, 7) |
| 163 | +print(len(decompress(data_wbits_8, deflate.RAW, 8))) |
| 164 | +print(len(decompress(data_wbits_8, deflate.RAW, 9))) |
| 165 | +decompress_error(data_wbits_10, deflate.RAW) |
| 166 | +decompress_error(data_wbits_10, deflate.RAW, 9) |
| 167 | +print(len(decompress(data_wbits_10, deflate.RAW, 10))) |
| 168 | + |
| 169 | +# zlib header sets the size, so works with wbits unset or wbits >= 10. |
| 170 | +data_wbits_10_zlib = b"(\x91\xcbH\xcd\xc9\xc9g\x18\xe9\x00\x08Fz\x18\x00\xc3`\xa4'\x03`2\x18\xe99\x01\x98\x13Fz\xfe\x07\xe6\xff\x91\x9e\xff\x81\xf9\x7f\xa4\xe7\x7f`\xfe\x1f\xba\xf9?#5''\x1f\x00[\xbc\x04)" |
| 171 | +print(len(decompress(data_wbits_10_zlib, deflate.ZLIB))) |
| 172 | +decompress_error(data_wbits_10_zlib, deflate.ZLIB, 9) |
| 173 | +print(len(decompress(data_wbits_10_zlib, deflate.ZLIB, 10))) |
| 174 | +print(len(decompress(data_wbits_10_zlib))) |
0 commit comments