| // Copyright 2024 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "patchmaker/compression_util.h" |
| |
| #include <optional> |
| |
| #include <base/files/file_path.h> |
| #include <base/files/file_util.h> |
| |
| #include "patchmaker/file_util.h" |
| |
| // We do not want to perform the most aggressive compression here for |
| // performance reasons. This utility is used to perform a quick |
| // comparison to understand the effectiveness of compression, and for |
| // this purpose an intermediate compression level is effective. |
| #define ZSTD_COMPRESSION_LEVEL_TEST 5 |
| |
| namespace util { |
| |
| bool Compress(const brillo::Blob& in, brillo::Blob* out) { |
| ScopedZstdCtx ctx(ZSTD_createCCtx()); |
| size_t compressed_size; |
| |
| if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx.get(), ZSTD_c_compressionLevel, |
| ZSTD_COMPRESSION_LEVEL_TEST))) { |
| return false; |
| } |
| |
| // Ensure our buffer has enough space to hold compressed contents, as in |
| // theory it could be larger than the input file. |
| out->resize(ZSTD_compressBound(in.size())); |
| |
| // Compression step. |
| compressed_size = ZSTD_compress2(ctx.get(), |
| // Destination. |
| out->data(), out->size(), |
| // Source. |
| in.data(), in.size()); |
| out->resize(compressed_size); |
| |
| if (ZSTD_isError(compressed_size)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool Decompress(const brillo::Blob& in, brillo::Blob* out) { |
| out->resize(ZSTD_getFrameContentSize(in.data(), in.size())); |
| |
| // Compression step. |
| size_t decompressed_size = ZSTD_decompress( |
| // Destination. |
| out->data(), out->size(), |
| // Source. |
| in.data(), in.size()); |
| out->resize(decompressed_size); |
| |
| // Clean up |
| if (ZSTD_isError(decompressed_size)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| std::optional<size_t> GetCompressedSize(const base::FilePath& path) { |
| std::optional<brillo::Blob> src; |
| |
| src = ReadFileToBlob(path); |
| if (!src.has_value()) { |
| LOG(ERROR) << "Failed to load file into blob"; |
| return std::nullopt; |
| } |
| |
| brillo::Blob dst; |
| if (!Compress(*src, &dst)) { |
| LOG(ERROR) << "Compress call failed"; |
| return std::nullopt; |
| } |
| |
| return dst.size(); |
| } |
| |
| } // namespace util |