/** * @file encrypt.cpp * * Implementation of functions for compression and decompressing MPQ data. */ #include #include #include #include #include #include "encrypt.h" namespace devilution { uint32_t PkwareCompress(std::byte *srcData, uint32_t size) { // Stack buffer covers typical network messages and MPQ sectors (≤ 4096). // Falls back to heap for larger payloads. constexpr size_t StackBufSize = 4096 * 2 + 64; uint8_t stackBuf[StackBufSize]; size_t dstCap = static_cast(size) * 2 + 64; uint8_t *dst; std::unique_ptr heapBuf; if (dstCap <= StackBufSize) { dst = stackBuf; } else { heapBuf = std::make_unique(dstCap); dst = heapBuf.get(); } size_t dstSize = dstCap; int rc = mpqfs_pk_implode( reinterpret_cast(srcData), size, dst, &dstSize, /*dict_bits=*/6); if (rc == 0 && dstSize < size) { std::memcpy(srcData, dst, dstSize); return static_cast(dstSize); } // Compression didn't help — return original size. return size; } uint32_t PkwareDecompress(std::byte *inBuff, uint32_t recvSize, size_t maxBytes) { // Stack buffer covers most decompressed network payloads. // Falls back to heap for larger buffers. constexpr size_t StackBufSize = 8192; uint8_t stackBuf[StackBufSize]; uint8_t *out; std::unique_ptr heapBuf; if (maxBytes <= StackBufSize) { out = stackBuf; } else { heapBuf = std::make_unique(maxBytes); out = heapBuf.get(); } size_t outSize = maxBytes; int rc = mpqfs_pk_explode( reinterpret_cast(inBuff), recvSize, out, &outSize); if (rc != 0) return 0; std::memcpy(inBuff, out, outSize); return static_cast(outSize); } } // namespace devilution