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