/* * 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 // presumes zstd library is installed #include 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 Resources::decompress(const std::span &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); }