diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/embed.cpp | 67 | ||||
-rw-r--r-- | lib/embed.h | 29 | ||||
-rw-r--r-- | lib/embed_zstd.cpp | 62 |
3 files changed, 81 insertions, 77 deletions
diff --git a/lib/embed.cpp b/lib/embed.cpp index c3b0286..07af38f 100644 --- a/lib/embed.cpp +++ b/lib/embed.cpp @@ -1,70 +1,17 @@ -/* - * 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) +template <> +Resources<Compression::None>::Resources(const std::span<const unsigned char> &) { - if(!info.dictionary.empty()) { - dictPtr = ZSTD_createDDict(info.dictionary.data(), info.dictionary.size()); - } } -Resources::~Resources() -{ - if(dictPtr != nullptr) { - ZSTD_freeDDict(dictPtr); - } -} +template <> +Resources<Compression::None>::~Resources() = default; -[[nodiscard]] std::span<unsigned char> Resources::decompress(const std::span<const unsigned char> &entry) +template <> +[[nodiscard]] std::vector<unsigned char> Resources<Compression::None>::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); + return { entry.begin(), entry.end() }; } - diff --git a/lib/embed.h b/lib/embed.h index 566b14c..bd041ff 100644 --- a/lib/embed.h +++ b/lib/embed.h @@ -1,34 +1,29 @@ #pragma once -#include <span> -#include <string> -#include <unordered_map> -#include <frozen/unordered_map.h> #include <frozen/string.h> +#include <frozen/unordered_map.h> +#include <span> +#include <vector> -namespace embed { +namespace embed +{ enum Compression { None, Zstd }; -struct ResourceData { - Compression compression = None; - std::span<const unsigned char> dictionary; -}; - -class Resources { +template <Compression c> +class Resources +{ public: - explicit Resources(const ResourceData &info); + Resources() = default; + explicit Resources(const std::span<const unsigned char> &dictionary); + ~Resources(); - [[nodiscard]] - std::span<unsigned char> decompress(const std::span<const unsigned char> &entry); + [[nodiscard]] std::vector<unsigned char> decompress(const std::span<const unsigned char> &entry); -private: - const ResourceData m_info; }; // class } - diff --git a/lib/embed_zstd.cpp b/lib/embed_zstd.cpp new file mode 100644 index 0000000..d9be35a --- /dev/null +++ b/lib/embed_zstd.cpp @@ -0,0 +1,62 @@ +#include "embed.h" +#include <cassert> +#include <zstd.h> + +using namespace embed; + +ZSTD_DDict *dictPtr = nullptr; + +template <> +Resources<Compression::Zstd>::Resources(const std::span<const unsigned char> &dictionary) +{ + if(!dictionary.empty()) { + dictPtr = ZSTD_createDDict(dictionary.data(), dictionary.size()); + } +} + +template <> +Resources<Compression::Zstd>::~Resources() +{ + if(dictPtr != nullptr) { + ZSTD_freeDDict(dictPtr); + } +} + +template <> +[[nodiscard]] std::vector<unsigned char> Resources<Compression::Zstd>::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); + //data<unsigned char> rBuff(new unsigned char[rSize], rSize, true); + std::vector<unsigned char> 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; +} |