MegaGlest/source/shared_lib/sources/compression/compression_utils.cpp

377 lines
12 KiB
C++

// ==============================================================
// 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 <limits.h>
#include <string>
#include <vector>
#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<const char *> 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<const char *> 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<unsigned char *,unsigned long> 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<unsigned char *,unsigned long> 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);
}
}}