1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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;
}
|