mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-09-24 15:54:12 +00:00
270 lines
6.2 KiB
C++
270 lines
6.2 KiB
C++
#include "CompressionUtility.h"
|
|
#include "malloc.h"
|
|
#include <cstring>
|
|
#include "zlib.h"
|
|
#include "minizip/unzip.h"
|
|
|
|
|
|
#define dir_delimter '/'
|
|
#define MAX_FILENAME 512
|
|
#define READ_SIZE 8192
|
|
|
|
/// <summary>
|
|
/// Compress given buffer as GZIP.
|
|
/// Dont forget to free out buffer!!!!
|
|
/// </summary>
|
|
/// <param name="input"></param>
|
|
/// <param name="input_size"></param>
|
|
/// <param name="ppvOut"></param>
|
|
/// <param name="out_size"></param>
|
|
/// <returns></returns>
|
|
int CompressionUtility::CompressAsGZip(const void* input, size_t input_size, void** ppvOut, size_t& out_size)
|
|
{
|
|
z_stream zlib_stream;
|
|
zlib_stream.next_in = (Bytef*)input;
|
|
zlib_stream.avail_in = (uInt)input_size;
|
|
zlib_stream.next_out = Z_NULL;
|
|
zlib_stream.avail_out = Z_NULL;
|
|
zlib_stream.zalloc = (alloc_func)0;
|
|
zlib_stream.zfree = (free_func)0;
|
|
zlib_stream.opaque = 0;
|
|
int ret = deflateInit2(&zlib_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (16 + MAX_WBITS), 8, Z_DEFAULT_STRATEGY);
|
|
|
|
unsigned full_length = 2000;
|
|
unsigned half_length = input_size / 2;
|
|
|
|
unsigned compLength = full_length;
|
|
unsigned char* comp = (unsigned char*)malloc(compLength);
|
|
|
|
bool done = false;
|
|
|
|
while (!done)
|
|
{
|
|
if (zlib_stream.total_out >= compLength)
|
|
{
|
|
// Increase size of output buffer
|
|
unsigned char* uncomp2 = (unsigned char*)malloc(compLength + half_length);
|
|
memcpy(uncomp2, comp, compLength);
|
|
compLength += half_length;
|
|
free(comp);
|
|
comp = uncomp2;
|
|
}
|
|
|
|
zlib_stream.next_out = (Bytef*)(comp + zlib_stream.total_out);
|
|
zlib_stream.avail_out = compLength - zlib_stream.total_out;
|
|
|
|
// Deflate another chunk.
|
|
ret = deflate(&zlib_stream, Z_FINISH);
|
|
if (Z_STREAM_END == ret)
|
|
{
|
|
done = true;
|
|
}
|
|
else if (Z_OK != ret)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (Z_OK != deflateEnd(&zlib_stream))
|
|
{
|
|
free(comp);
|
|
return ret;
|
|
}
|
|
|
|
*ppvOut = (void*)comp;
|
|
out_size = zlib_stream.total_out;
|
|
|
|
return ret;
|
|
}
|
|
/// <summary>
|
|
/// Decompress given buffer.
|
|
/// Dont forget to free out buffer!!!!
|
|
/// </summary>
|
|
/// <param name="input"></param>
|
|
/// <param name="input_size"></param>
|
|
/// <param name="ppvOut"></param>
|
|
/// <param name="out_size"></param>
|
|
/// <returns></returns>
|
|
int CompressionUtility::DecompressGZip(const void* input, size_t input_size, void** ppvOut, size_t& out_size)
|
|
{
|
|
z_stream zlib_stream;
|
|
zlib_stream.next_in = (Bytef*)input;
|
|
zlib_stream.avail_in = (uInt)input_size;
|
|
zlib_stream.next_out = Z_NULL;
|
|
zlib_stream.avail_out = Z_NULL;
|
|
zlib_stream.zalloc = (alloc_func)0;
|
|
zlib_stream.zfree = (free_func)0;
|
|
zlib_stream.opaque = Z_NULL;
|
|
|
|
int ret = inflateInit2(&zlib_stream, (16 + MAX_WBITS));
|
|
if (Z_OK != ret)
|
|
{
|
|
return ret;
|
|
}
|
|
unsigned full_length = input_size;
|
|
unsigned half_length = input_size / 2;
|
|
|
|
unsigned uncompLength = full_length;
|
|
unsigned char* uncomp = (unsigned char*)malloc(uncompLength);
|
|
|
|
bool done = false;
|
|
|
|
while (!done)
|
|
{
|
|
if (zlib_stream.total_out >= uncompLength)
|
|
{
|
|
// Increase size of output buffer
|
|
unsigned char* uncomp2 = (unsigned char*)malloc(uncompLength + half_length);
|
|
memcpy(uncomp2, uncomp, uncompLength);
|
|
uncompLength += half_length;
|
|
free(uncomp);
|
|
uncomp = uncomp2;
|
|
}
|
|
|
|
zlib_stream.next_out = (Bytef*)(uncomp + zlib_stream.total_out);
|
|
zlib_stream.avail_out = uncompLength - zlib_stream.total_out;
|
|
|
|
// Inflate another chunk.
|
|
ret = inflate(&zlib_stream, Z_SYNC_FLUSH);
|
|
if (Z_STREAM_END == ret)
|
|
{
|
|
done = true;
|
|
}
|
|
else if (Z_OK != ret)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (Z_OK != inflateEnd(&zlib_stream))
|
|
{
|
|
free(uncomp);
|
|
return ret;
|
|
}
|
|
|
|
*ppvOut = (void*)uncomp;
|
|
out_size = zlib_stream.total_out;
|
|
return ret;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns inflated first file inside the ZIP container,
|
|
/// rest are ignored!!!!!
|
|
/// </summary>
|
|
/// <param name="input"></param>
|
|
/// <param name="input_size"></param>
|
|
/// <param name="ppvOut"></param>
|
|
/// <param name="out_size"></param>
|
|
/// <returns></returns>
|
|
int CompressionUtility::DecompressPKZip(const char* fn, void** ppvOut, size_t& out_size)
|
|
{
|
|
// Open the zip file
|
|
unzFile zipfile = unzOpen(fn);
|
|
if (nullptr == zipfile)
|
|
{
|
|
// file not found
|
|
return -1;
|
|
}
|
|
|
|
// Get info about the zip file
|
|
unz_global_info global_info;
|
|
if (UNZ_OK != unzGetGlobalInfo(zipfile, &global_info))
|
|
{
|
|
// could not read file global info
|
|
unzClose(zipfile);
|
|
return -1;
|
|
}
|
|
|
|
// Buffer to hold data read from the zip file.
|
|
//char read_buffer[READ_SIZE];
|
|
|
|
// Loop to extract all files
|
|
for (uLong i = 0; i < global_info.number_entry; ++i)
|
|
{
|
|
// Get info about current file.
|
|
unz_file_info file_info;
|
|
char filename[MAX_FILENAME];
|
|
if (unzGetCurrentFileInfo(
|
|
zipfile,
|
|
&file_info,
|
|
filename,
|
|
MAX_FILENAME,
|
|
NULL, 0, NULL, 0) != UNZ_OK)
|
|
{
|
|
// could not read file info
|
|
unzClose(zipfile);
|
|
return -1;
|
|
}
|
|
|
|
// Check if this entry is a directory or file.
|
|
const size_t filename_length = strlen(filename);
|
|
if (filename[filename_length - 1] == dir_delimter)
|
|
{
|
|
// Entry is a directory, skip it
|
|
}
|
|
else
|
|
{
|
|
// Entry is a file, so extract it.
|
|
if (unzOpenCurrentFile(zipfile) != UNZ_OK)
|
|
{
|
|
// could not open file
|
|
unzClose(zipfile);
|
|
return -1;
|
|
}
|
|
|
|
unsigned full_length = READ_SIZE * 2;
|
|
unsigned half_length = READ_SIZE;
|
|
|
|
unsigned uncompLength = full_length;
|
|
unsigned char* uncomp = (unsigned char*)malloc(uncompLength);
|
|
|
|
size_t total_out = 0;
|
|
int error = UNZ_OK;
|
|
do
|
|
{
|
|
if (total_out >= uncompLength)
|
|
{
|
|
// Increase size of output buffer
|
|
unsigned char* uncomp2 = (unsigned char*)malloc(uncompLength + half_length);
|
|
memcpy(uncomp2, uncomp, uncompLength);
|
|
uncompLength += half_length;
|
|
free(uncomp);
|
|
uncomp = uncomp2;
|
|
}
|
|
|
|
error = unzReadCurrentFile(zipfile, uncomp + total_out, uncompLength - total_out);
|
|
if (error < 0)
|
|
{
|
|
// something happened
|
|
unzCloseCurrentFile(zipfile);
|
|
unzClose(zipfile);
|
|
return -1;
|
|
}
|
|
|
|
// Write data to buffer.
|
|
if (error > 0)
|
|
{
|
|
total_out += error;
|
|
}
|
|
} while (error > 0);
|
|
|
|
*ppvOut = (void*)uncomp;
|
|
out_size = total_out;
|
|
}
|
|
|
|
unzCloseCurrentFile(zipfile);
|
|
|
|
// Go the the next entry listed in the zip file.
|
|
//if ((i + 1) < global_info.number_entry)
|
|
//{
|
|
// if (unzGoToNextFile(zipfile) != UNZ_OK)
|
|
// {
|
|
// printf("cound not read next file\n");
|
|
// unzClose(zipfile);
|
|
// return -1;
|
|
// }
|
|
//}
|
|
}
|
|
|
|
unzClose(zipfile);
|
|
|
|
return UNZ_OK;
|
|
}
|