2020-09-28 19:19:27 +02:00
|
|
|
/*
|
|
|
|
* IXGzipCodec.cpp
|
|
|
|
* Author: Benjamin Sergeant
|
|
|
|
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "IXGzipCodec.h"
|
|
|
|
|
2020-09-30 23:25:41 +02:00
|
|
|
#include "IXBench.h"
|
2020-09-28 19:19:27 +02:00
|
|
|
#include <array>
|
2020-09-28 20:01:59 +02:00
|
|
|
#include <string.h>
|
2020-09-28 19:19:27 +02:00
|
|
|
|
|
|
|
#ifdef IXWEBSOCKET_USE_ZLIB
|
|
|
|
#include <zlib.h>
|
|
|
|
#endif
|
|
|
|
|
2020-09-30 23:25:41 +02:00
|
|
|
#ifdef IXWEBSOCKET_USE_DEFLATE
|
|
|
|
#include <libdeflate.h>
|
|
|
|
#endif
|
|
|
|
|
2020-09-28 19:19:27 +02:00
|
|
|
namespace ix
|
|
|
|
{
|
|
|
|
#ifdef IXWEBSOCKET_USE_ZLIB
|
|
|
|
std::string gzipCompress(const std::string& str)
|
|
|
|
{
|
2020-09-30 23:25:41 +02:00
|
|
|
#ifdef IXWEBSOCKET_USE_DEFLATE
|
|
|
|
int compressionLevel = 6;
|
|
|
|
struct libdeflate_compressor* compressor;
|
|
|
|
|
|
|
|
compressor = libdeflate_alloc_compressor(compressionLevel);
|
|
|
|
|
|
|
|
const void* uncompressed_data = str.data();
|
|
|
|
size_t uncompressed_size = str.size();
|
|
|
|
void* compressed_data;
|
|
|
|
size_t actual_compressed_size;
|
|
|
|
size_t max_compressed_size;
|
|
|
|
|
|
|
|
max_compressed_size = libdeflate_gzip_compress_bound(compressor, uncompressed_size);
|
|
|
|
compressed_data = malloc(max_compressed_size);
|
|
|
|
|
|
|
|
if (compressed_data == NULL)
|
|
|
|
{
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
actual_compressed_size = libdeflate_gzip_compress(
|
|
|
|
compressor, uncompressed_data, uncompressed_size, compressed_data, max_compressed_size);
|
|
|
|
|
|
|
|
libdeflate_free_compressor(compressor);
|
|
|
|
|
|
|
|
if (actual_compressed_size == 0)
|
|
|
|
{
|
|
|
|
free(compressed_data);
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string out;
|
|
|
|
out.assign(reinterpret_cast<char*>(compressed_data), actual_compressed_size);
|
|
|
|
free(compressed_data);
|
|
|
|
|
|
|
|
return out;
|
|
|
|
#else
|
2020-09-28 19:19:27 +02:00
|
|
|
z_stream zs; // z_stream is zlib's control structure
|
|
|
|
memset(&zs, 0, sizeof(zs));
|
|
|
|
|
|
|
|
// deflateInit2 configure the file format: request gzip instead of deflate
|
|
|
|
const int windowBits = 15;
|
|
|
|
const int GZIP_ENCODING = 16;
|
|
|
|
|
|
|
|
deflateInit2(&zs,
|
|
|
|
Z_DEFAULT_COMPRESSION,
|
|
|
|
Z_DEFLATED,
|
|
|
|
windowBits | GZIP_ENCODING,
|
|
|
|
8,
|
|
|
|
Z_DEFAULT_STRATEGY);
|
|
|
|
|
|
|
|
zs.next_in = (Bytef*) str.data();
|
|
|
|
zs.avail_in = (uInt) str.size(); // set the z_stream's input
|
|
|
|
|
|
|
|
int ret;
|
|
|
|
char outbuffer[32768];
|
|
|
|
std::string outstring;
|
|
|
|
|
|
|
|
// retrieve the compressed bytes blockwise
|
|
|
|
do
|
|
|
|
{
|
|
|
|
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
|
|
|
|
zs.avail_out = sizeof(outbuffer);
|
|
|
|
|
|
|
|
ret = deflate(&zs, Z_FINISH);
|
|
|
|
|
|
|
|
if (outstring.size() < zs.total_out)
|
|
|
|
{
|
|
|
|
// append the block to the output string
|
|
|
|
outstring.append(outbuffer, zs.total_out - outstring.size());
|
|
|
|
}
|
|
|
|
} while (ret == Z_OK);
|
|
|
|
|
|
|
|
deflateEnd(&zs);
|
|
|
|
|
|
|
|
return outstring;
|
2020-09-30 23:25:41 +02:00
|
|
|
#endif
|
2020-09-28 19:19:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool gzipDecompress(const std::string& in, std::string& out)
|
|
|
|
{
|
|
|
|
z_stream inflateState;
|
2020-09-28 20:56:49 +02:00
|
|
|
memset(&inflateState, 0, sizeof(inflateState));
|
2020-09-28 19:19:27 +02:00
|
|
|
|
|
|
|
inflateState.zalloc = Z_NULL;
|
|
|
|
inflateState.zfree = Z_NULL;
|
|
|
|
inflateState.opaque = Z_NULL;
|
|
|
|
inflateState.avail_in = 0;
|
|
|
|
inflateState.next_in = Z_NULL;
|
|
|
|
|
|
|
|
if (inflateInit2(&inflateState, 16 + MAX_WBITS) != Z_OK)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
inflateState.avail_in = (uInt) in.size();
|
|
|
|
inflateState.next_in = (unsigned char*) (const_cast<char*>(in.data()));
|
|
|
|
|
|
|
|
const int kBufferSize = 1 << 14;
|
|
|
|
std::array<unsigned char, kBufferSize> compressBuffer;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
inflateState.avail_out = (uInt) kBufferSize;
|
|
|
|
inflateState.next_out = &compressBuffer.front();
|
|
|
|
|
|
|
|
int ret = inflate(&inflateState, Z_SYNC_FLUSH);
|
|
|
|
|
|
|
|
if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR)
|
|
|
|
{
|
|
|
|
inflateEnd(&inflateState);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
out.append(reinterpret_cast<char*>(&compressBuffer.front()),
|
|
|
|
kBufferSize - inflateState.avail_out);
|
|
|
|
} while (inflateState.avail_out == 0);
|
|
|
|
|
|
|
|
inflateEnd(&inflateState);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} // namespace ix
|