blob: aa4239240f0130c04e3b41fd7eef42f61738bfaa [file] [log] [blame]
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright OpenBMC Authors
#include "zstd_decompressor.hpp"
#include "logging.hpp"
#ifdef HAVE_ZSTD
#include <zstd.h>
#endif
#include <boost/asio/buffer.hpp>
#include <cstddef>
#include <optional>
#ifdef HAVE_ZSTD
ZstdDecompressor::ZstdDecompressor() : dctx(ZSTD_createDStream())
{
ZSTD_initDStream(dctx);
}
#else
ZstdDecompressor::ZstdDecompressor() {};
#endif
std::optional<boost::asio::const_buffer> ZstdDecompressor::decompress(
[[maybe_unused]] boost::asio::const_buffer buffIn)
{
#ifdef HAVE_ZSTD
compressionBuf.clear();
ZSTD_inBuffer input = {buffIn.data(), buffIn.size(), 0};
// Note, this loop is prone to compression bombs, decompressing chunks that
// appear very small, but decompress to be very large, given that they're
// highly decompressible. This algorithm assumes that at this time, the
// whole file will fit in ram.
while (input.pos != input.size)
{
constexpr size_t frameSize = 4096;
auto buffer = compressionBuf.prepare(frameSize);
ZSTD_outBuffer output = {buffer.data(), buffer.size(), 0};
const size_t ret = ZSTD_decompressStream(dctx, &output, &input);
if (ZSTD_isError(ret) != 0)
{
BMCWEB_LOG_ERROR("Decompression Failed with code {}:{}", ret,
ZSTD_getErrorName(ret));
return std::nullopt;
}
compressionBuf.commit(output.pos);
}
return compressionBuf.cdata();
#else
BMCWEB_LOG_CRITICAL("Attempt to decompress, but libzstd not enabled");
return std::nullopt;
#endif
}
ZstdDecompressor::~ZstdDecompressor()
{
#ifdef HAVE_ZSTD
ZSTD_freeDStream(dctx);
#endif
}