blob: bc59fd41c0815787d40e967d9931ab632376b4d8 [file] [log] [blame] [edit]
///////////////////////////////////////////////////////////////////////////////
// //
// DxilCompression.cpp //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
///////////////////////////////////////////////////////////////////////////////
//
// Helper wrapper functions for zlib deflate and inflate. Entirely
// self-contained, only depends on IMalloc interface.
//
#include "dxc/DxilCompression/DxilCompression.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/WinIncludes.h"
#include "miniz.h"
typedef size_t ZlibSize_t;
typedef const Bytef ZlibInputBytesf;
namespace {
//
// A resource managment class for a zlib stream that calls the appropriate init
// and end routines.
//
class Zlib {
public:
enum Operation { INFLATE, DEFLATE };
Zlib(Operation Op, IMalloc *pAllocator)
: m_Stream{}, m_Op(Op), m_Initalized(false) {
m_Stream = {};
if (pAllocator) {
m_Stream.zalloc = ZAlloc;
m_Stream.zfree = ZFree;
m_Stream.opaque = pAllocator;
}
int ret = Z_ERRNO;
if (Op == INFLATE) {
ret = inflateInit(&m_Stream);
} else {
ret = deflateInit(&m_Stream, Z_DEFAULT_COMPRESSION);
}
if (ret != Z_OK) {
m_InitializationResult = TranslateZlibResult(ret);
return;
}
m_Initalized = true;
}
~Zlib() {
if (m_Initalized) {
if (m_Op == INFLATE) {
inflateEnd(&m_Stream);
} else {
deflateEnd(&m_Stream);
}
}
}
z_stream *GetStream() {
if (m_Initalized)
return &m_Stream;
return nullptr;
}
hlsl::ZlibResult GetInitializationResult() const {
return m_InitializationResult;
}
static hlsl::ZlibResult TranslateZlibResult(int zlibResult) {
switch (zlibResult) {
default:
return hlsl::ZlibResult::InvalidData;
case Z_MEM_ERROR:
case Z_BUF_ERROR:
return hlsl::ZlibResult::OutOfMemory;
}
}
private:
z_stream m_Stream;
Operation m_Op;
bool m_Initalized;
hlsl::ZlibResult m_InitializationResult = hlsl::ZlibResult::Success;
static void *ZAlloc(void *context, ZlibSize_t items, ZlibSize_t size) {
IMalloc *mallocif = (IMalloc *)context;
return mallocif->Alloc(items * size);
}
static void ZFree(void *context, void *pointer) {
IMalloc *mallocif = (IMalloc *)context;
mallocif->Free(pointer);
}
};
} // namespace
hlsl::ZlibResult hlsl::ZlibDecompress(IMalloc *pMalloc,
const void *pCompressedBuffer,
size_t BufferSizeInBytes,
void *pUncompressedBuffer,
size_t UncompressedBufferSize) {
Zlib zlib(Zlib::INFLATE, pMalloc);
z_stream *pStream = zlib.GetStream();
if (!pStream)
return zlib.GetInitializationResult();
pStream->avail_in = BufferSizeInBytes;
pStream->next_in = (ZlibInputBytesf *)pCompressedBuffer;
pStream->next_out = (Byte *)pUncompressedBuffer;
pStream->avail_out = UncompressedBufferSize;
// Compression should finish in one call because of the call to deflateBound.
int status = inflate(pStream, Z_FINISH);
if (status != Z_STREAM_END) {
return Zlib::TranslateZlibResult(status);
}
return ZlibResult::Success;
}
hlsl::ZlibResult hlsl::ZlibCompress(IMalloc *pMalloc, const void *pData,
size_t pDataSize, void *pUserData,
ZlibCallbackFn *Callback,
size_t *pOutCompressedSize) {
Zlib zlib(Zlib::DEFLATE, pMalloc);
z_stream *pStream = zlib.GetStream();
if (!pStream)
return zlib.GetInitializationResult();
const size_t UpperBound = deflateBound(pStream, pDataSize);
void *pDestBuffer = Callback(pUserData, UpperBound);
if (!pDestBuffer)
return ZlibResult::OutOfMemory;
pStream->next_in = (ZlibInputBytesf *)pData;
pStream->avail_in = pDataSize;
pStream->next_out = (Byte *)pDestBuffer;
pStream->avail_out = UpperBound;
int status = deflate(pStream, Z_FINISH);
if (status != Z_STREAM_END) {
return Zlib::TranslateZlibResult(status);
}
*pOutCompressedSize = pStream->total_out;
return ZlibResult::Success;
}