blob: aa4239240f0130c04e3b41fd7eef42f61738bfaa [file] [log] [blame]
Ed Tanousb2539062024-03-12 16:58:35 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
3
4#include "zstd_decompressor.hpp"
5
6#include "logging.hpp"
7
8#ifdef HAVE_ZSTD
9#include <zstd.h>
10#endif
11#include <boost/asio/buffer.hpp>
12
13#include <cstddef>
14#include <optional>
15
16#ifdef HAVE_ZSTD
17ZstdDecompressor::ZstdDecompressor() : dctx(ZSTD_createDStream())
18{
19 ZSTD_initDStream(dctx);
20}
21#else
22ZstdDecompressor::ZstdDecompressor() {};
23#endif
24
25std::optional<boost::asio::const_buffer> ZstdDecompressor::decompress(
26 [[maybe_unused]] boost::asio::const_buffer buffIn)
27{
28#ifdef HAVE_ZSTD
29 compressionBuf.clear();
30 ZSTD_inBuffer input = {buffIn.data(), buffIn.size(), 0};
31
32 // Note, this loop is prone to compression bombs, decompressing chunks that
33 // appear very small, but decompress to be very large, given that they're
34 // highly decompressible. This algorithm assumes that at this time, the
35 // whole file will fit in ram.
36 while (input.pos != input.size)
37 {
38 constexpr size_t frameSize = 4096;
39 auto buffer = compressionBuf.prepare(frameSize);
40 ZSTD_outBuffer output = {buffer.data(), buffer.size(), 0};
41 const size_t ret = ZSTD_decompressStream(dctx, &output, &input);
42 if (ZSTD_isError(ret) != 0)
43 {
44 BMCWEB_LOG_ERROR("Decompression Failed with code {}:{}", ret,
45 ZSTD_getErrorName(ret));
46 return std::nullopt;
47 }
48 compressionBuf.commit(output.pos);
49 }
50 return compressionBuf.cdata();
51#else
52 BMCWEB_LOG_CRITICAL("Attempt to decompress, but libzstd not enabled");
53
54 return std::nullopt;
55#endif
56}
57
58ZstdDecompressor::~ZstdDecompressor()
59{
60#ifdef HAVE_ZSTD
61 ZSTD_freeDStream(dctx);
62#endif
63}