diff options
Diffstat (limited to 'lib/zstd.cpp')
-rw-r--r-- | lib/zstd.cpp | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/lib/zstd.cpp b/lib/zstd.cpp new file mode 100644 index 0000000..d2c27bc --- /dev/null +++ b/lib/zstd.cpp @@ -0,0 +1,59 @@ +#include "compressionctx.h" +#include <cassert> +#include <zstd.h> + +using namespace embed; + +ZSTD_DDict *dictPtr = nullptr; + +ZstdCompressionCtx::ZstdCompressionCtx(const std::span<const uint8_t> &dictionary) +{ + if(!dictionary.empty()) { + dictPtr = ZSTD_createDDict(dictionary.data(), dictionary.size()); + } +} + +ZstdCompressionCtx::~ZstdCompressionCtx() +{ + if(dictPtr != nullptr) { + ZSTD_freeDDict(dictPtr); + } +} + +[[nodiscard]] +std::vector<uint8_t> ZstdCompressionCtx::decompress(const std::span<const uint8_t> &entry) const +{ + /* Read the content size from the frame header. For simplicity we require + * that it is always present. By default, zstd will write the content size + * in the header when it is known. If you can't guarantee that the frame + * content size is always written into the header, either use streaming + * decompression, or ZSTD_decompressBound(). + */ + unsigned long long const rSize = ZSTD_getFrameContentSize(entry.data(), entry.size()); + assert(rSize != ZSTD_CONTENTSIZE_ERROR); //, "%s: not compressed by zstd!", fname); + assert(rSize != ZSTD_CONTENTSIZE_UNKNOWN); //, "%s: original size unknown!", fname); + std::vector<uint8_t> rBuff(rSize); + + /* Check that the dictionary ID matches. + * If a non-zstd dictionary is used, then both will be zero. + * By default zstd always writes the dictionary ID into the frame. + * Zstd will check if there is a dictionary ID mismatch as well. + */ + unsigned const expectedDictID = ZSTD_getDictID_fromDDict(dictPtr); + unsigned const actualDictID = ZSTD_getDictID_fromFrame(entry.data(), entry.size()); + assert(actualDictID == expectedDictID); //"DictID mismatch: expected %u got %u", + + /* Decompress using the dictionary. + * If you need to control the decompression parameters, then use the + * advanced API: ZSTD_DCtx_setParameter(), ZSTD_DCtx_refDDict(), and + * ZSTD_decompressDCtx(). + */ + ZSTD_DCtx *const dctx = ZSTD_createDCtx(); + assert(dctx != NULL); //, "ZSTD_createDCtx() failed!"); + size_t const dSize = ZSTD_decompress_usingDDict(dctx, rBuff.data(), rSize, entry.data(), entry.size(), dictPtr); + /* When zstd knows the content size, it will error if it doesn't match. */ + assert(dSize == rSize); //, "Impossible because zstd will check this condition!"); + + ZSTD_freeDCtx(dctx); + return rBuff; +} |