Last active
August 30, 2017 06:22
-
-
Save benwills/356d8d1e2a2ef2a9203197b846338ec3 to your computer and use it in GitHub Desktop.
zlib inflate, where the file/buffer contains multiple streams.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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