// Standard C #include #include #include #include // System #include // zlib #include enum { BUFFER_SIZE = 8192 }; static void usage(void) { (void) fprintf(stderr, "stream [-d] infile outfile\n"); } static void error(const char *msg) { perror(msg); exit(EXIT_FAILURE); } static void print_zlib_error(const char *operation, int error) { if ( error == Z_ERRNO ) { (void) fprintf(stderr, "%s error: %s\n", operation, strerror(errno)); } else { (void) fprintf(stderr, "%s error: %s\n", operation, zError(error)); } } int do_compress(FILE *in_file, FILE *out_file, int compress_level) { z_stream strm = { 0 }; int error = deflateInit(&strm, compress_level); if ( error ) { return error; } unsigned char in_buffer[BUFFER_SIZE]; unsigned char out_buffer[BUFFER_SIZE]; int flush = Z_NO_FLUSH; do { strm.avail_in = fread(in_buffer, 1, BUFFER_SIZE, in_file); if ( ferror(in_file) ) { deflateEnd(&strm); return Z_ERRNO; } flush = feof(in_file) ? Z_FINISH : Z_NO_FLUSH; strm.next_in = in_buffer; do { strm.avail_out = BUFFER_SIZE; strm.next_out = out_buffer; error = deflate(&strm, flush); size_t have = BUFFER_SIZE - strm.avail_out; if ( fwrite(out_buffer, 1, have, out_file) != have || ferror(out_file) ) { deflateEnd(&strm); return Z_ERRNO; } } while ( strm.avail_out == 0 ); } while ( flush != Z_FINISH ); deflateEnd(&strm); return Z_OK; } int do_uncompress(FILE *in_file, FILE *out_file) { z_stream strm = { 0 }; int error = inflateInit(&strm); if ( error ) { return error; } unsigned char in_buffer[BUFFER_SIZE]; unsigned char out_buffer[BUFFER_SIZE]; do { strm.avail_in = fread(in_buffer, 1, BUFFER_SIZE, in_file); if ( ferror(in_file) ) { inflateEnd(&strm); return Z_ERRNO; } if ( strm.avail_in == 0 ) { break; } strm.next_in = in_buffer; do { strm.avail_out = BUFFER_SIZE; strm.next_out = out_buffer; error = inflate(&strm, Z_NO_FLUSH); switch ( error ) { case Z_NEED_DICT: error = Z_DATA_ERROR; /* and fall through */ case Z_DATA_ERROR: case Z_MEM_ERROR: (void) inflateEnd(&strm); return error; default: break; } size_t have = BUFFER_SIZE - strm.avail_out; if ( fwrite(out_buffer, 1, have, out_file) != have || ferror(out_file) ) { (void) inflateEnd(&strm); return Z_ERRNO; } } while ( strm.avail_out == 0 ); } while ( error != Z_STREAM_END ); inflateEnd(&strm); return error == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; } int main(int argc, char *argv[]) { enum { COMPRESSION_STD = 5, COMPRESSION_BEST = 9 }; int decompress = 0; int compress_level = COMPRESSION_STD; int opt = 0; while ( (opt = getopt(argc, argv, "dl")) != -1 ) { switch ( opt ) { case 'd': decompress = 1; break; case 'l': compress_level = COMPRESSION_BEST; break; case '?': default: usage(); return EXIT_SUCCESS; } } argc -= optind; argv += optind; if ( argc != 2 ) { usage(); return EXIT_FAILURE; } FILE *in_file = fopen(argv[0], "rb"); if ( in_file == NULL ) { error("fopen() on in_file failed"); } FILE *out_file = fopen(argv[1], "wb"); if ( out_file == NULL ) { (void) fclose(in_file); error("fopen() on out_file failed"); } if ( !decompress ) { int error = do_compress(in_file, out_file, compress_level); if ( error ) { print_zlib_error("compression", error); } } else { int error = do_uncompress(in_file, out_file); if ( error ) { print_zlib_error("extraction", error); } } (void) fclose(out_file); (void) fclose(in_file); return EXIT_SUCCESS; }