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
60
61
62
63
64
65
66
67
68
69
70
|
/*
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
#include "embed.h"
#include <zstd.h> // presumes zstd library is installed
#include <cassert>
using namespace embed;
ZSTD_DDict* dictPtr = nullptr;
Resources::Resources(const ResourceData &info)
: m_info(info)
{
if(!info.dictionary.empty()) {
dictPtr = ZSTD_createDDict(info.dictionary.data(), info.dictionary.size());
}
}
Resources::~Resources()
{
if(dictPtr != nullptr) {
ZSTD_freeDDict(dictPtr);
}
}
[[nodiscard]] std::span<unsigned char> Resources::decompress(const std::span<const unsigned char> &entry)
{
/* 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);
auto* rBuff = new unsigned char[(size_t) 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, 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 std::span(rBuff, rSize);
}
|