Skip to content

Instantly share code, notes, and snippets.

@benwills
Last active August 30, 2017 06:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benwills/356d8d1e2a2ef2a9203197b846338ec3 to your computer and use it in GitHub Desktop.
Save benwills/356d8d1e2a2ef2a9203197b846338ec3 to your computer and use it in GitHub Desktop.
zlib inflate, where the file/buffer contains multiple streams.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <zlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <inttypes.h>
/*
i didn't find any code - in the documentation or otherwise - that
showed how to inflate a file or buffer that might contain multiple
streams/files.
more specifically, i'm looking for a way to decompress a buffer
that's already in memory, so gzFile, et al, weren't what i was
looking for.
in order to decompress multiple streams in the same compressed buffer,
you must move the pointer sent to inflate(), byt strm.total_in bytes
after each read. you see this handled below with in_pos and in_byt.
*/
#define INPUT_FILE "filename.gz"
int
unz(z_stream *strm,
const void *src, unsigned long src_byt,
void *dst, unsigned long dst_byt)
{
strm->total_in = strm->avail_in = src_byt;
strm->total_out = strm->avail_out = dst_byt;
strm->next_in = (Bytef*)src;
strm->next_out = (Bytef*)dst;
strm->zalloc = Z_NULL;
strm->zfree = Z_NULL;
strm->opaque = Z_NULL;
int ret = -1;
// 15 = window bits
// +32 = detect if using gzip or zlib
ret = inflateInit2(strm, (15 + 32));
if (ret == Z_OK)
ret = inflate(strm, Z_FINISH);
inflateEnd(strm);
return ret;
}
int
main()
{
const char *fnm = INPUT_FILE;
struct stat fp_stat;
if (0 == stat(fnm, &fp_stat))
printf("bytes: %d\n", (int)fp_stat.st_size);
printf("allocating: zip_buf\n");fflush(stdout);
void *zip_buf = calloc(1, fp_stat.st_size);
unsigned long zip_byt = (int)fp_stat.st_size;
printf("allocating: unz_buf\n");fflush(stdout);
unsigned long unz_byt = (1024UL * 1024UL * 8UL); // 8mb is fine here
void *unz_buf = calloc(1, zip_byt);
printf("reading file to memory\n");fflush(stdout);
FILE *fp = fopen(fnm, "rb");
fseek(fp, 0, SEEK_SET);
fread(zip_buf, fp_stat.st_size, 1, fp);
fclose(fp);
printf("unzipping\n");fflush(stdout);
z_stream strm = {0};
int ret = 0;
int cnt = 0;
void *in_pos = zip_buf;
unsigned long in_byt = zip_byt;
while (Z_STREAM_END == unz(&strm, in_pos, in_byt, unz_buf, unz_byt))
{
// printf("unz_buf:\n%.*s\n", (int)strm.total_out, (char*)unz_buf);
// fflush(stdout);
in_pos += strm.total_in;
in_byt -= strm.total_in;
printf("read: %ld\n", strm.total_in);
printf("left: %ld\n", in_byt);
printf("totl: %d\n", ++cnt);
printf("\n");
fflush(stdout);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment