#include "stdafx.h"

#include "zlib/zlib.h"

using namespace std;

namespace {
	const int inflateMaxSize = 8 * 1024 * 1024;
}

bool zlib_inflate(const vector<char>& src, vector<char>& dest)
{
	z_stream z;
	z.zalloc = Z_NULL;
	z.zfree = Z_NULL;
	z.opaque = Z_NULL;
	z.next_in = Z_NULL;
	z.avail_in = 0;
	if (inflateInit(&z) != Z_OK) {
		return false;
	}

	z.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(&src[0]));
	z.avail_in = src.size();
	char buf[8 * 1024];
	z.next_out = reinterpret_cast<Bytef*>(buf);
	z.avail_out = sizeof buf;

	dest.clear();

	int status;
	do {
		status = inflate(&z, Z_NO_FLUSH);
		if (status == Z_OK || status == Z_STREAM_END) {
			dest.insert(dest.end(), &buf[0], &buf[sizeof buf - z.avail_out]);
			if (dest.size() > inflateMaxSize)
                break;
            z.next_out = reinterpret_cast<Bytef*>(buf);
			z.avail_out = sizeof buf;
		}
	} while (status == Z_OK);

	inflateEnd(&z);
	return status == Z_STREAM_END && dest.size() <= inflateMaxSize;
}

bool zlib_deflate(const vector<char>& src, vector<char>& dest)
{
	z_stream z;
	z.zalloc = Z_NULL;
	z.zfree = Z_NULL;
	z.opaque = Z_NULL;
	if (deflateInit(&z, Z_DEFAULT_COMPRESSION) != Z_OK) {
		return false;
	}

	z.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(&src[0]));
	z.avail_in = src.size();
	char buf[8 * 1024];
	z.next_out = reinterpret_cast<Bytef*>(buf);
	z.avail_out = sizeof buf;

	dest.clear();

	int status;
	do {
		status = deflate(&z, Z_FINISH);
		if (status == Z_OK || status == Z_STREAM_END) {
			dest.insert(dest.end(), &buf[0], &buf[sizeof buf - z.avail_out]);
			z.next_out = reinterpret_cast<Bytef*>(buf);
			z.avail_out = sizeof buf;
		}
	} while (status == Z_OK);

	deflateEnd(&z);
	return status == Z_STREAM_END;
}
