Source code for kiel.compression.snappy
from __future__ import absolute_import
import struct
try:
import snappy as snappy
snappy_available = True
except ImportError: # pragma: no cover
snappy_available = False
from six import BytesIO
DEFAULT_VERSION = 1
MIN_COMPAT_VERSION = 1
MAGIC_HEADER = (
-126, b'S', b'N', b'A', b'P', b'P', b'Y', 0,
DEFAULT_VERSION, MIN_COMPAT_VERSION
)
BLOCK_SIZE = 32 * 1024 # 32kb, in bytes
raw_header = struct.pack("!bccccccbii", *MAGIC_HEADER)
[docs]def compress(data):
"""
Compresses given data via the snappy algorithm.
The result is preceded with a header containing the string 'SNAPPY' and the
default and min-compat versions (both ``1``).
The block size for the compression is hard-coded at 32kb.
If ``python-snappy`` is not installed a ``RuntimeError`` is raised.
"""
if not snappy_available:
raise RuntimeError("Snappy compression unavailable.")
buff = BytesIO()
buff.write(raw_header)
for block_num in range(0, len(data), BLOCK_SIZE):
block = data[block_num:block_num + BLOCK_SIZE]
compressed = snappy.compress(block)
buff.write(struct.pack("!i", len(compressed)))
buff.write(compressed)
result = buff.getvalue()
buff.close()
return result
[docs]def decompress(data):
"""
Decompresses the given data via the snappy algorithm.
If ``python-snappy`` is not installed a ``RuntimeError`` is raised.
"""
if not snappy_available:
raise RuntimeError("Snappy compression unavailable.")
buff_offset = len(raw_header) # skip the header
length = len(data) - len(raw_header)
output = BytesIO()
while buff_offset <= length:
block_size = struct.unpack_from("!i", data, buff_offset)[0]
buff_offset += struct.calcsize("!i")
block = struct.unpack_from("!%ds" % block_size, data, buff_offset)[0]
buff_offset += block_size
output.write(snappy.uncompress(block))
result = output.getvalue()
output.close()
return result