// ============================================================== // This file is part of MegaGlest Shared Library (www.megaglest.org) // // Copyright (C) 2013 Mark Vejvoda // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published // by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version // ============================================================== // This file is based on example3.c - Demonstrates how to use miniz.c's deflate() // and inflate() functions for simple file compression. // Public domain, May 15 2011, Rich Geldreich, richgel99@gmail.com. See "unlicense" // statement at the end of tinfl.c. // For simplicity, this example is limited to files smaller than 4GB, but this // is not a limitation of miniz.c. #include "compression_utils.h" #include "miniz/miniz.c" #include #include #include #include "conversion.h" #include "platform_util.h" #include "util.h" using namespace Shared::Util; namespace Shared{ namespace CompressionUtil{ typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint; #define my_max(a,b) (((a) > (b)) ? (a) : (b)) #define my_min(a,b) (((a) < (b)) ? (a) : (b)) #define BUF_SIZE (1024 * 1024) static uint8 s_inbuf[BUF_SIZE]; static uint8 s_outbuf[BUF_SIZE]; int zipfile_tool(int argc, const char *argv[]) { const char *pMode = NULL; FILE *pInfile = NULL, *pOutfile = NULL; uint infile_size = 0; int level = Z_BEST_COMPRESSION; z_stream stream; int p = 1; const char *pSrc_filename = NULL; const char *pDst_filename = NULL; long file_loc = 0; if(SystemFlags::VERBOSE_MODE_ENABLED) printf("miniz.c version: %s\n", MZ_VERSION); if (argc < 4) { if(SystemFlags::VERBOSE_MODE_ENABLED) { printf("Usage: example3 [options] [mode:c or d] infile outfile\n"); printf("\nModes:\n"); printf("c - Compresses file infile to a zlib stream in file outfile\n"); printf("d - Decompress zlib stream in file infile to file outfile\n"); printf("\nOptions:\n"); printf("-l[0-10] - Compression level, higher values are slower.\n"); } return EXIT_FAILURE; } while ((p < argc) && (argv[p][0] == '-')) { switch (argv[p][1]) { case 'l': { level = atoi(&argv[1][2]); if ((level < 0) || (level > 10)) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Invalid level!\n"); return EXIT_FAILURE; } break; } default: { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Invalid option: %s\n", argv[p]); return EXIT_FAILURE; } } p++; } if ((argc - p) < 3) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Must specify mode, input filename, and output filename after options!\n"); return EXIT_FAILURE; } else if ((argc - p) > 3) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Too many filenames!\n"); return EXIT_FAILURE; } pMode = argv[p++]; if (!strchr("cCdD", pMode[0])) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Invalid mode!\n"); if(SystemFlags::VERBOSE_MODE_ENABLED) return EXIT_FAILURE; } pSrc_filename = argv[p++]; pDst_filename = argv[p++]; if(SystemFlags::VERBOSE_MODE_ENABLED)printf("Mode: %c, Level: %d\nInput File: \"%s\"\nOutput File: \"%s\"\n", pMode[0], level, pSrc_filename, pDst_filename); // Open input file. pInfile = fopen(pSrc_filename, "rb"); if (!pInfile) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Failed opening input file!\n"); return EXIT_FAILURE; } // Determine input file's size. fseek(pInfile, 0, SEEK_END); file_loc = ftell(pInfile); fseek(pInfile, 0, SEEK_SET); if ((file_loc < 0) || (file_loc > INT_MAX)) { // This is not a limitation of miniz or tinfl, but this example. printf("File is too large to be processed by this example.\n"); fclose(pInfile); return EXIT_FAILURE; } infile_size = (uint)file_loc; // Open output file. pOutfile = fopen(pDst_filename, "wb"); if (!pOutfile) { printf("Failed opening output file!\n"); fclose(pInfile); return EXIT_FAILURE; } if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Input file size: %u\n", infile_size); // Init the z_stream memset(&stream, 0, sizeof(stream)); stream.next_in = s_inbuf; stream.avail_in = 0; stream.next_out = s_outbuf; stream.avail_out = BUF_SIZE; if ((pMode[0] == 'c') || (pMode[0] == 'C')) { // Compression. uint infile_remaining = infile_size; if (deflateInit(&stream, level) != Z_OK) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("deflateInit() failed!\n"); if(pInfile) fclose(pInfile); if(pOutfile) fclose(pOutfile); return EXIT_FAILURE; } for ( ; ; ) { int status; if (!stream.avail_in) { // Input buffer is empty, so read more bytes from input file. uint n = my_min(BUF_SIZE, infile_remaining); if (fread(s_inbuf, 1, n, pInfile) != n) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Failed reading from input file!\n"); fclose(pInfile); if(pOutfile) fclose(pOutfile); return EXIT_FAILURE; } stream.next_in = s_inbuf; stream.avail_in = n; infile_remaining -= n; //printf("Input bytes remaining: %u\n", infile_remaining); } status = deflate(&stream, infile_remaining ? Z_NO_FLUSH : Z_FINISH); if ((status == Z_STREAM_END) || (!stream.avail_out)) { // Output buffer is full, or compression is done, so write buffer to output file. uint n = BUF_SIZE - stream.avail_out; if (fwrite(s_outbuf, 1, n, pOutfile) != n) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Failed writing to output file!\n"); if(pInfile) fclose(pInfile); fclose(pOutfile); return EXIT_FAILURE; } stream.next_out = s_outbuf; stream.avail_out = BUF_SIZE; } if (status == Z_STREAM_END) { break; } else if (status != Z_OK) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("deflate() failed with status %i!\n", status); if(pInfile) fclose(pInfile); if(pOutfile) fclose(pOutfile); return EXIT_FAILURE; } } if (deflateEnd(&stream) != Z_OK) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("deflateEnd() failed!\n"); if(pInfile) fclose(pInfile); if(pOutfile) fclose(pOutfile); return EXIT_FAILURE; } } else if ((pMode[0] == 'd') || (pMode[0] == 'D')) { // Decompression. uint infile_remaining = infile_size; if (inflateInit(&stream)) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("inflateInit() failed!\n"); if(pInfile) fclose(pInfile); if(pOutfile) fclose(pOutfile); return EXIT_FAILURE; } for ( ; ; ) { int status; if (!stream.avail_in) { // Input buffer is empty, so read more bytes from input file. uint n = my_min(BUF_SIZE, infile_remaining); if (fread(s_inbuf, 1, n, pInfile) != n) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Failed reading from input file!\n"); fclose(pInfile); if(pOutfile) fclose(pOutfile); return EXIT_FAILURE; } stream.next_in = s_inbuf; stream.avail_in = n; infile_remaining -= n; } status = inflate(&stream, Z_SYNC_FLUSH); if ((status == Z_STREAM_END) || (!stream.avail_out)) { // Output buffer is full, or decompression is done, so write buffer to output file. uint n = BUF_SIZE - stream.avail_out; if (fwrite(s_outbuf, 1, n, pOutfile) != n) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Failed writing to output file!\n"); if(pInfile) fclose(pInfile); fclose(pOutfile); return EXIT_FAILURE; } stream.next_out = s_outbuf; stream.avail_out = BUF_SIZE; } if (status == Z_STREAM_END) { break; } else if (status != Z_OK) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("inflate() failed with status %i!\n", status); if(pInfile) fclose(pInfile); if(pOutfile) fclose(pOutfile); return EXIT_FAILURE; } } if (inflateEnd(&stream) != Z_OK) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("inflateEnd() failed!\n"); if(pInfile) fclose(pInfile); if(pOutfile) fclose(pOutfile); return EXIT_FAILURE; } } else { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Invalid mode!\n"); if(pInfile) fclose(pInfile); if(pOutfile) fclose(pOutfile); return EXIT_FAILURE; } fclose(pInfile); pInfile = 0; if (EOF == fclose(pOutfile)) { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Failed writing to output file!\n"); return EXIT_FAILURE; } if(SystemFlags::VERBOSE_MODE_ENABLED) { printf("Total input bytes: %u\n", (mz_uint32)stream.total_in); printf("Total output bytes: %u\n", (mz_uint32)stream.total_out); printf("Success.\n"); } return EXIT_SUCCESS; } bool compressFileToZIPFile(string inFile, string outFile, int compressionLevel) { string options = "-l" + intToStr(compressionLevel); std::vector argv; argv.push_back(options.c_str()); argv.push_back("c"); argv.push_back(inFile.c_str()); argv.push_back(outFile.c_str()); int result = zipfile_tool((int)argv.size(), &argv[0]); return(result == EXIT_SUCCESS ? true : false); } bool extractFileFromZIPFile(string inFile, string outFile) { std::vector argv; argv.push_back("-l10"); argv.push_back("d"); argv.push_back(inFile.c_str()); argv.push_back(outFile.c_str()); int result = zipfile_tool((int)argv.size(), &argv[0]); return(result == EXIT_SUCCESS ? true : false); } std::pair compressMemoryToMemory(unsigned char *input, unsigned long input_len, int compressionLevel) { // Like compress() but with more control, level may range from 0 (storing) to 9 (max. compression) unsigned long compressed_buffer_len = input_len + 100; unsigned char *compressed_buffer = new unsigned char[compressed_buffer_len+1]; memset(compressed_buffer,0,compressed_buffer_len+1); unsigned char *decompressed_buffer = new unsigned char[input_len+1]; memcpy(decompressed_buffer,input,input_len); //printf("compress2 start size: %lu\n",input_len); int result = compress2(compressed_buffer, &compressed_buffer_len, decompressed_buffer, input_len, compressionLevel); if(result != Z_OK) { string msg = string("Invalid compress2 return value: ") + intToStr(result); throw megaglest_runtime_error(msg.c_str()); } //printf("compress2 returned: %d start size: %lu end size: %lu\n",result,input_len,compressed_buffer_len); delete [] decompressed_buffer; return make_pair(compressed_buffer,compressed_buffer_len); } std::pair extractMemoryToMemory(unsigned char *input, unsigned long input_len, unsigned long max_output_len) { // Like compress() but with more control, level may range from 0 (storing) to 9 (max. compression) unsigned long decompressed_buffer_len = max_output_len; unsigned char *decompressed_buffer = new unsigned char[decompressed_buffer_len+1]; memset(decompressed_buffer,0,decompressed_buffer_len+1); //printf("#1uncompress start size: %lu\n",input_len); unsigned char *compressed_buffer = new unsigned char[input_len+1]; memcpy(compressed_buffer,input,input_len); //printf("#2uncompress start size: %lu\n",input_len); //int result = uncompress(decompressed_buffer, &decompressed_buffer_len, compressed_buffer, input_len); int result = uncompress(decompressed_buffer, &decompressed_buffer_len, compressed_buffer, input_len); if(result != Z_OK) { string msg = string("Invalid uncompress return value: ") + intToStr(result); throw megaglest_runtime_error(msg.c_str()); } //printf("uncompress returned: %d start size: %lu end size: %lu\n",result,input_len,decompressed_buffer_len); delete [] compressed_buffer; return make_pair(decompressed_buffer,decompressed_buffer_len); } }}