| Ed Tanous | b253906 | 2024-03-12 16:58:35 -0700 | [diff] [blame] | 1 | // 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 | 
|  | 17 | ZstdDecompressor::ZstdDecompressor() : dctx(ZSTD_createDStream()) | 
|  | 18 | { | 
|  | 19 | ZSTD_initDStream(dctx); | 
|  | 20 | } | 
|  | 21 | #else | 
|  | 22 | ZstdDecompressor::ZstdDecompressor() {}; | 
|  | 23 | #endif | 
|  | 24 |  | 
|  | 25 | std::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 |  | 
|  | 58 | ZstdDecompressor::~ZstdDecompressor() | 
|  | 59 | { | 
|  | 60 | #ifdef HAVE_ZSTD | 
|  | 61 | ZSTD_freeDStream(dctx); | 
|  | 62 | #endif | 
|  | 63 | } |