Files
Aerofoil/PortabilityLayer/DeflateCodec.cpp
2020-10-17 18:04:28 -04:00

88 lines
1.6 KiB
C++

#include "DeflateCodec.h"
#include "GpIOStream.h"
#include "MemoryManager.h"
#ifdef GP_ZLIB_BUILTIN
#include <zlib.h>
#else
#include "zlib.h"
#endif
namespace
{
static voidpf ZlibAllocShim(voidpf opaque, uInt items, uInt size)
{
return static_cast<PortabilityLayer::MemoryManager*>(opaque)->Alloc(items * size);
}
void ZlibFreeShim(voidpf opaque, voidpf address)
{
static_cast<PortabilityLayer::MemoryManager*>(opaque)->Release(address);
}
}
namespace PortabilityLayer
{
bool DeflateCodec::DecompressStream(GpIOStream *stream, size_t inSize, void *outBuffer, size_t outSize)
{
z_stream zstream;
zstream.zalloc = ZlibAllocShim;
zstream.zfree = ZlibFreeShim;
zstream.opaque = MemoryManager::GetInstance();
if (inflateInit2(&zstream, -15) != Z_OK)
return false;
const size_t bufferSize = 1024;
uint8_t buffer[1024];
zstream.avail_out = outSize;
zstream.next_out = static_cast<Bytef*>(outBuffer);
zstream.avail_in = 0;
zstream.next_in = buffer;
bool failed = false;
for (;;)
{
if (zstream.avail_in == 0)
{
const size_t sizeToRead = (bufferSize < inSize) ? bufferSize : inSize;
if (sizeToRead == 0)
{
// Ran out of input
failed = true;
break;
}
if (stream->Read(buffer, sizeToRead) != sizeToRead)
{
failed = true;
break;
}
zstream.avail_in = sizeToRead;
zstream.next_in = buffer;
}
int result = inflate(&zstream, Z_NO_FLUSH);
if (result == Z_STREAM_END)
{
failed = (zstream.avail_out != 0);
break;
}
if (result != Z_OK)
{
failed = true;
break;
}
}
inflateEnd(&zstream);
return !failed;
}
}