// Standard C #include #include #include // System #include // zlib #include static void usage(void) { (void) fprintf(stderr, "compress [-d] infile outfile\n"); } static void error(const char *msg) { perror(msg); exit(EXIT_FAILURE); } size_t get_filesize(FILE *file) { long current_pos = ftell(file); if ( current_pos == -1 ) { error("ftell() failed"); } if ( fseek(file, 0, SEEK_END) != 0 ) { error("fseek() failed"); } long size = ftell(file); if ( size == -1 ) { error("ftell() failed"); } if ( fseek(file, current_pos, SEEK_SET) != 0 ) { error("fseek() failed"); } return (size_t) size; } void do_compress(FILE *in_file, FILE *out_file, int compress_level) { size_t in_size = get_filesize(in_file); (void) fwrite(&in_size, sizeof in_size, 1, out_file); unsigned char *in_data = malloc(in_size); (void) fread(in_data, 1, in_size, in_file); size_t out_size = compressBound(in_size); unsigned char *out_data = malloc(out_size); const int error = compress2(out_data, &out_size, in_data, in_size, compress_level); if ( !error ) { (void) fwrite(out_data, 1, out_size, out_file); } else { (void) fprintf(stderr, "Error: %s\n", zError(error)); } free(out_data); free(in_data); } void do_uncompress(FILE *in_file, FILE *out_file) { size_t in_size = get_filesize(in_file); unsigned char *in_data = malloc(in_size); (void) fread(in_data, 1, in_size, in_file); size_t out_size = 0; memcpy(&out_size, in_data, sizeof out_size); unsigned char *out_data = malloc(out_size); const size_t compressed_data_size = in_size - sizeof(size_t); size_t consumed_size = compressed_data_size; const int error = uncompress2(out_data, &out_size, in_data + sizeof(size_t), &consumed_size); if ( !error ) { if ( compressed_data_size != consumed_size ) { (void) fputs("Warning: Trailing data detected.\n", stderr); } (void) fwrite(out_data, 1, out_size, out_file); } else { (void) fprintf(stderr, "Error: %s\n", zError(error)); } free(out_data); free(in_data); } 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(); } FILE *in_file = fopen(argv[0], "rb"); FILE *out_file = fopen(argv[1], "wb"); if ( !decompress ) { do_compress(in_file, out_file, compress_level); } else { do_uncompress(in_file, out_file); } (void) fclose(out_file); (void) fclose(in_file); return EXIT_SUCCESS; }