In-memory decompression with zlib
Can I 开发者_运维问答read a zlib compressed file in memory without actually extracting it to disk? It would be nice if you could provide a snippet.
Here's a zLib inflate routine that takes a buffer in memory and decompresses into the provided output buffer. This is a 'one-shot' function, in that it attempts to inflate the entire input buffer all at once, and assumes you've given it enough space to fit it all. It is also possible to write a multi-shot function that dynamically grows the destination buffer as needed.
int inflate(const void *src, int srcLen, void *dst, int dstLen) {
z_stream strm = {0};
strm.total_in = strm.avail_in = srcLen;
strm.total_out = strm.avail_out = dstLen;
strm.next_in = (Bytef *) src;
strm.next_out = (Bytef *) dst;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
int err = -1;
int ret = -1;
err = inflateInit2(&strm, (15 + 32)); //15 window bits, and the +32 tells zlib to to detect if using gzip or zlib
if (err == Z_OK) {
err = inflate(&strm, Z_FINISH);
if (err == Z_STREAM_END) {
ret = strm.total_out;
}
else {
inflateEnd(&strm);
return err;
}
}
else {
inflateEnd(&strm);
return err;
}
inflateEnd(&strm);
return ret;
}
Explanation:
src: the source buffer containing the compressed (gzip or zlib) data
srcLen: the length of the source buffer
dst: the destination buffer, into which the output will be written
dstLen: the length of the destination buffer
Return values:
Z_BUF_ERROR: if dstLen is not large enough to fit the inflated data
Z_MEM_ERROR: if there's insufficient memory to perform the decompression
Z_DATA_ERROR: if the input data was corrupt
Otherwise, the return value is the number of bytes written to dst.
Solution provided by Raj Advani does not work for multistream zlib buffer. Solution for gzip data:
void decompress(Bytef *src, int src_len, Bytef *dst, int dst_len)
{
z_stream strm = {0};
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
while (src_len > 0)
{
strm.total_in = strm.avail_in = src_len;
strm.total_out = strm.avail_out = dst_len;
strm.next_in = src;
strm.next_out = (Bytef *) dst;
assert(inflateInit2(&strm, (MAX_WBITS + 16)) == Z_OK);
decompress_block(&strm, dst);
unsigned int processed = src_len - strm.avail_in;
src_len -= processed;
src += processed;
}
}
int decompress_block(z_stream *strm, void *dst)
{
int ret;
do
{
ret = inflate(strm, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR && ret != Z_NEED_DICT && ret != Z_MEM_ERROR && ret != Z_DATA_ERROR);
assert(strm->avail_out > 0);
}
while (ret != Z_STREAM_END);
inflateEnd(strm);
assert(write(1, dst, strm->total_out) == strm->total_out);
return 0;
}
https://github.com/uvoteam/gunzip_mmap
精彩评论