overte/libraries/shared/src/Gzip.cpp
2018-05-04 16:26:41 -07:00

155 lines
3.9 KiB
C++

//
// Gzip.cpp
// libraries/shared/src
//
// Created by Seth Alves on 2015-08-03.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Gzip.h"
#include <zlib.h>
const int GZIP_WINDOWS_BIT = 31;
const int GZIP_CHUNK_SIZE = 4096;
const int DEFAULT_MEM_LEVEL = 8;
bool gunzip(QByteArray source, QByteArray &destination) {
destination.clear();
if (source.length() == 0) {
return true;
}
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
int status = inflateInit2(&strm, GZIP_WINDOWS_BIT);
if (status != Z_OK) {
return false;
}
char *sourceData = source.data();
int sourceDataLength = source.length();
for (;;) {
int chunkSize = qMin(GZIP_CHUNK_SIZE, sourceDataLength);
if (chunkSize <= 0) {
break;
}
strm.next_in = (unsigned char*)sourceData;
strm.avail_in = chunkSize;
sourceData += chunkSize;
sourceDataLength -= chunkSize;
for (;;) {
char out[GZIP_CHUNK_SIZE];
strm.next_out = (unsigned char*)out;
strm.avail_out = GZIP_CHUNK_SIZE;
status = inflate(&strm, Z_NO_FLUSH);
switch (status) {
case Z_NEED_DICT:
status = Z_DATA_ERROR;
// FALLTHRU
case Z_DATA_ERROR:
case Z_MEM_ERROR:
case Z_STREAM_ERROR:
inflateEnd(&strm);
return false;
}
int available = (GZIP_CHUNK_SIZE - strm.avail_out);
if (available > 0) {
destination.append((char*)out, available);
}
if (strm.avail_out != 0) {
break;
}
}
if (status == Z_STREAM_END) {
break;
}
}
inflateEnd(&strm);
return status == Z_STREAM_END;
}
bool gzip(QByteArray source, QByteArray &destination, int compressionLevel) {
destination.clear();
if (source.length() == 0) {
return true;
}
int flushOrFinish = 0;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.next_in = Z_NULL;
strm.avail_in = 0;
int status = deflateInit2(&strm,
qMax(Z_DEFAULT_COMPRESSION, qMin(9, compressionLevel)),
Z_DEFLATED,
GZIP_WINDOWS_BIT,
DEFAULT_MEM_LEVEL,
Z_DEFAULT_STRATEGY);
if (status != Z_OK) {
return false;
}
char *sourceData = source.data();
int sourceDataLength = source.length();
for (;;) {
int chunkSize = qMin(GZIP_CHUNK_SIZE, sourceDataLength);
strm.next_in = (unsigned char*)sourceData;
strm.avail_in = chunkSize;
sourceData += chunkSize;
sourceDataLength -= chunkSize;
if (sourceDataLength <= 0) {
flushOrFinish = Z_FINISH;
} else {
flushOrFinish = Z_NO_FLUSH;
}
for (;;) {
char out[GZIP_CHUNK_SIZE];
strm.next_out = (unsigned char*)out;
strm.avail_out = GZIP_CHUNK_SIZE;
status = deflate(&strm, flushOrFinish);
if (status == Z_STREAM_ERROR) {
deflateEnd(&strm);
return false;
}
int available = (GZIP_CHUNK_SIZE - strm.avail_out);
if (available > 0) {
destination.append((char*)out, available);
}
if (strm.avail_out != 0) {
break;
}
}
if (flushOrFinish == Z_FINISH) {
break;
}
}
deflateEnd(&strm);
return status == Z_STREAM_END;
}