3#ifndef LIBZARR_CODECS_ZSTD_HPP
4#define LIBZARR_CODECS_ZSTD_HPP
6#ifndef LIBZARR_HAS_ZSTD
7#error "libzarr/codecs_zstd.hpp requires libzstd: define LIBZARR_HAS_ZSTD and link zstd"
16#include "libzarr/detail/common.hpp"
24namespace zarr::detail {
30#ifndef LIBZARR_ZSTD_DECODE_ONLY
33 ZstdCctxGuard() : cctx_(ZSTD_createCCtx()) {}
34 ZstdCctxGuard(
const ZstdCctxGuard&) =
delete;
35 ZstdCctxGuard& operator=(
const ZstdCctxGuard&) =
delete;
36 ZstdCctxGuard(ZstdCctxGuard&&) =
delete;
37 ZstdCctxGuard& operator=(ZstdCctxGuard&&) =
delete;
38 ~ZstdCctxGuard() { ZSTD_freeCCtx(cctx_); }
39 [[nodiscard]] ZSTD_CCtx* get()
const {
return cctx_; }
48 ZstdDctxGuard() : dctx_(ZSTD_createDCtx()) {}
49 ZstdDctxGuard(
const ZstdDctxGuard&) =
delete;
50 ZstdDctxGuard& operator=(
const ZstdDctxGuard&) =
delete;
51 ZstdDctxGuard(ZstdDctxGuard&&) =
delete;
52 ZstdDctxGuard& operator=(ZstdDctxGuard&&) =
delete;
53 ~ZstdDctxGuard() { ZSTD_freeDCtx(dctx_); }
54 [[nodiscard]] ZSTD_DCtx* get()
const {
return dctx_; }
60#ifndef LIBZARR_ZSTD_DECODE_ONLY
63inline Bytes zstd_compress_bytes(
const Bytes& src,
int level,
bool checksum,
const char* what) {
64 const ZstdCctxGuard cctx;
65 if (cctx.get() ==
nullptr) {
66 throw error(std::string(what) +
": ZSTD_createCCtx failed");
68 ZSTD_CCtx_setParameter(cctx.get(), ZSTD_c_compressionLevel, level);
69 ZSTD_CCtx_setParameter(cctx.get(), ZSTD_c_checksumFlag, checksum ? 1 : 0);
70 Bytes out(ZSTD_compressBound(src.size()));
71 const std::size_t n = ZSTD_compress2(cctx.get(), out.data(), out.size(), src.data(), src.size());
72 if (ZSTD_isError(n) != 0) {
73 throw error(std::string(what) +
": zstd compression failed (" + ZSTD_getErrorName(n) +
")");
83inline Bytes zstd_decompress_bytes(
const Bytes& src, std::optional<std::uint64_t> expected,
85 const unsigned long long content = ZSTD_getFrameContentSize(src.data(), src.size());
86 if (content == ZSTD_CONTENTSIZE_ERROR) {
87 throw error(std::string(what) +
": corrupt zstd frame");
89 if (content != ZSTD_CONTENTSIZE_UNKNOWN) {
90 if (expected && content != *expected) {
91 throw error(std::string(what) +
": zstd frame decodes to " + std::to_string(content) +
92 " bytes, expected " + std::to_string(*expected));
94 Bytes out(checked_size(content, what));
95 const std::size_t n = ZSTD_decompress(out.data(), out.size(), src.data(), src.size());
96 if (ZSTD_isError(n) != 0 || n != out.size()) {
97 throw error(std::string(what) +
": zstd decompression failed");
104 const ZstdDctxGuard dctx;
105 if (dctx.get() ==
nullptr) {
106 throw error(std::string(what) +
": ZSTD_createDCtx failed");
110 out.resize(checked_size(*expected, what));
112 out.resize(std::max<std::size_t>(src.size() * 3, 64));
114 ZSTD_inBuffer in{src.data(), src.size(), 0};
115 ZSTD_outBuffer ob{out.data(), out.size(), 0};
117 const std::size_t ret = ZSTD_decompressStream(dctx.get(), &ob, &in);
118 if (ZSTD_isError(ret) != 0) {
119 throw error(std::string(what) +
": corrupt zstd data (" + ZSTD_getErrorName(ret) +
")");
124 if (ob.pos == ob.size) {
126 throw error(std::string(what) +
": decompressed data exceeds expected " +
127 std::to_string(*expected) +
" bytes");
129 out.resize(out.size() * 2);
131 ob.size = out.size();
132 }
else if (in.pos == in.size) {
133 throw error(std::string(what) +
": zstd data is truncated");
136 if (in.pos != in.size) {
137 throw error(std::string(what) +
": trailing garbage after zstd data");
139 if (expected && ob.pos != *expected) {
140 throw error(std::string(what) +
": decompressed to " + std::to_string(ob.pos) +
141 " bytes, expected " + std::to_string(*expected));
std::vector< std::uint8_t > Bytes
Owned byte buffer used throughout the value-based public API.
Definition types.hpp:42