diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index baf7d0f..07e3a2f 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -28,6 +28,8 @@ target_link_libraries(util common storm tempest + PRIVATE + zlib-1.2 ) if(WHOA_SYSTEM_LINUX OR WHOA_SYSTEM_MAC) diff --git a/src/util/Zlib.cpp b/src/util/Zlib.cpp new file mode 100644 index 0000000..0a437b8 --- /dev/null +++ b/src/util/Zlib.cpp @@ -0,0 +1,76 @@ +#include "util/Zlib.hpp" +#include +#include +#include + +int zlib_uncompress(Bytef* dest, uInt* destLen, const Bytef* source, uInt sourceLen) { + char buffer[47000]; + ZlibAllocBufferHeader header = { buffer, sizeof(buffer), buffer }; + + z_stream strm; + strm.next_in = const_cast(source); + strm.avail_in = sourceLen; + strm.next_out = dest; + strm.avail_out = *destLen; + strm.zalloc = &ZlibAlloc; + strm.zfree = &ZlibFree; + strm.opaque = &header; + + auto err = inflateInit(&strm); + if (err != Z_OK) { + return err; + } + + err = inflate(&strm, Z_FINISH); + if (err == Z_STREAM_END) { + *destLen = strm.total_out; + return inflateEnd(&strm); + } + + inflateEnd(&strm); + return err ? err : Z_BUF_ERROR; +} + +void* ZlibAlloc(void* opaque, uint32_t items, uint32_t size) { + auto buffer = static_cast(opaque); + STORM_ASSERT(buffer); + + uint32_t total = items * size; + + // Align to 4 bytes + if ((total & 3) != 0) { + total = (total & ~3) + 4; + } + + auto ptr = buffer->nextPtr; + size_t used = buffer->nextPtr - buffer->bufStart; + size_t remaining = buffer->bufSize - used; + + // Fall back to heap if stack allocated buffer is exhausted + if (total >= remaining) { + return STORM_ALLOC(total); + } + + buffer->nextPtr = ptr + total; + return ptr; +} + +void ZlibFree(void* opaque, void* ptr) { + auto* buffer = static_cast(opaque); + auto bufferStart = buffer->bufStart; + auto bufferEnd = buffer->bufStart + buffer->bufSize; + + // Only free if pointer is outside of stack allocated buffer + if (ptr < bufferStart || ptr >= bufferEnd) { + STORM_FREE(ptr); + } +} + +int32_t ZlibDecompress(void* dest, uint32_t* destLen, const void* source, uint32_t sourceLen) { + return zlib_uncompress( + static_cast(dest), + destLen, + static_cast(source), + sourceLen + ); +} diff --git a/src/util/Zlib.hpp b/src/util/Zlib.hpp new file mode 100644 index 0000000..79e7a5f --- /dev/null +++ b/src/util/Zlib.hpp @@ -0,0 +1,18 @@ +#ifndef UTIL_ZLIB_HPP +#define UTIL_ZLIB_HPP + +#include + +struct ZlibAllocBufferHeader { + char* nextPtr; + uint32_t bufSize; + char* bufStart; +}; + +void* ZlibAlloc(void* opaque, uint32_t items, uint32_t size); + +int32_t ZlibDecompress(void* dest, uint32_t* destLen, const void* source, uint32_t sourceLen); + +void ZlibFree(void* opaque, void* ptr); + +#endif