def uncompress(data): _out_data, _out_size = prepare(data) result = ffi.new('size_t*', 0) rc = C.snappy_validate_compressed_buffer(_out_data, _out_size) if not rc == C.SNAPPY_OK: raise UncompressError() rc = C.snappy_uncompressed_length(_out_data, _out_size, result) if not rc == C.SNAPPY_OK: raise UncompressError() _uncompressed_data = ffi.new('char[]', result[0]) rc = C.snappy_uncompress(_out_data, _out_size, _uncompressed_data, result) if rc != C.SNAPPY_OK: raise UncompressError() buf = ffi.buffer(ffi.cast('char*', _uncompressed_data), result[0]) return buf[:]
def flush(self): """All pending input is processed, and a string containing the remaining uncompressed output is returned. After calling flush(), the decompress() method cannot be called again; the only realistic action is to delete the object. """ if self._buf != b"": raise UncompressError("chunk truncated") return b""
def decompress(self, data): """Decompress 'data', returning a string containing the uncompressed data corresponding to at least part of the data in string. This data should be concatenated to the output produced by any preceding calls to the decompress() method. Some of the input data may be preserved in internal buffers for later processing. """ self._buf += data uncompressed = [] while True: if len(self._buf) < 4: return b"".join(uncompressed) chunk_type = struct.unpack("<L", self._buf[:4])[0] size = (chunk_type >> 8) chunk_type &= 0xff if not self._header_found: if (chunk_type != _IDENTIFIER_CHUNK or size != len(_STREAM_IDENTIFIER)): raise UncompressError("stream missing snappy identifier") self._header_found = True if (_RESERVED_UNSKIPPABLE[0] <= chunk_type and chunk_type < _RESERVED_UNSKIPPABLE[1]): raise UncompressError( "stream received unskippable but unknown chunk") if len(self._buf) < 4 + size: return b"".join(uncompressed) chunk, self._buf = self._buf[4:4 + size], self._buf[4 + size:] if chunk_type == _IDENTIFIER_CHUNK: if chunk != _STREAM_IDENTIFIER: raise UncompressError( "stream has invalid snappy identifier") continue if (_RESERVED_SKIPPABLE[0] <= chunk_type and chunk_type < _RESERVED_SKIPPABLE[1]): continue assert chunk_type in (_COMPRESSED_CHUNK, _UNCOMPRESSED_CHUNK) crc, chunk = chunk[:4], chunk[4:] if chunk_type == _COMPRESSED_CHUNK: chunk = _uncompress(chunk) if struct.pack("<L", _masked_crc32c(chunk)) != crc: raise UncompressError("crc mismatch") uncompressed.append(chunk)
def uncompress(data, decoding=None): if isinstance(data, unicode): raise UncompressError("It's only possible to uncompress bytes") if decoding: return _uncompress(data).decode(decoding) return _uncompress(data)
def flush(self): if self._buf != b"": raise UncompressError("chunk truncated") return b""