Decompressing a GZip Stream with Zlib
Contents
Introduction
This C++ program reads a file named input.txt.gz into memory, then uses the zlib library to decompress and print the data. After uncompression, the lyrics to Rick Astley's Never Gonna Give You Up will be printed.
Some things to note:
- The input.txt.gz file was generated using 7-zip by compressing input.txt (this file is also included in the download).
- The zipped file supplied contains a Code::Blocks project file and was written and tested under Windows using MinGW only.
- The necessary zlib files are included. They were obtained from the official zlib website. zdll.lib was renamed to libzdll.a in order to make it work with MinGW.
Download
You may download the source code and Code::Blocks project files here.
Source
Here is the source code listing for the program.
/* This C++ program uses zlib to read then decompress a gzipped file in memory. Author: Andrew Lim Chong Liang http://windrealm.org */ #include <cstdio> #include <string> #include <cstring> #include <cstdlib> #include "zlib.h" #include "zconf.h" using namespace std; bool gzipInflate( const std::string& compressedBytes, std::string& uncompressedBytes ) { if ( compressedBytes.size() == 0 ) { uncompressedBytes = compressedBytes ; return true ; } uncompressedBytes.clear() ; unsigned full_length = compressedBytes.size() ; unsigned half_length = compressedBytes.size() / 2; unsigned uncompLength = full_length ; char* uncomp = (char*) calloc( sizeof(char), uncompLength ); z_stream strm; strm.next_in = (Bytef *) compressedBytes.c_str(); strm.avail_in = compressedBytes.size() ; strm.total_out = 0; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; bool done = false ; if (inflateInit2(&strm, (16+MAX_WBITS)) != Z_OK) { free( uncomp ); return false; } while (!done) { // If our output buffer is too small if (strm.total_out >= uncompLength ) { // Increase size of output buffer char* uncomp2 = (char*) calloc( sizeof(char), uncompLength + half_length ); memcpy( uncomp2, uncomp, uncompLength ); uncompLength += half_length ; free( uncomp ); uncomp = uncomp2 ; } strm.next_out = (Bytef *) (uncomp + strm.total_out); strm.avail_out = uncompLength - strm.total_out; // Inflate another chunk. int err = inflate (&strm, Z_SYNC_FLUSH); if (err == Z_STREAM_END) done = true; else if (err != Z_OK) { break; } } if (inflateEnd (&strm) != Z_OK) { free( uncomp ); return false; } for ( size_t i=0; i<strm.total_out; ++i ) { uncompressedBytes += uncomp[ i ]; } free( uncomp ); return true ; } /* Reads a file into memory. */ bool loadBinaryFile( const std::string& filename, std::string& contents ) { // Open the gzip file in binary mode FILE* f = fopen( filename.c_str(), "rb" ); if ( f == NULL ) return false ; // Clear existing bytes in output vector contents.clear(); // Read all the bytes in the file int c = fgetc( f ); while ( c != EOF ) { contents += (char) c ; c = fgetc( f ); } fclose (f); return true ; } int main() { // Read the gzip file data into memory std::string fileData ; if ( !loadBinaryFile( "input.txt.gz", fileData ) ) { printf( "Error loading input file." ); return 0 ; } // Uncompress the file data std::string data ; if ( !gzipInflate( fileData, data ) ) { printf( "Error decompressing file." ); return 0 ; } // Print the data printf( "Data: \"" ); for ( size_t i=0; i<data.size(); ++i ) { printf( "%c", data[i] ); } printf ( "\"\n" ); return 0; }
Related Links
- Deusty Gzip compression/decompression - Objective-C version
- StackOverflow: How can I decompress a gzip stream with zlib?