From 746bcd25e22e492cd45a92bc9addb04cf81d208b Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Thu, 26 Mar 2020 11:28:58 +0200 Subject: Initial commit --- lib/embed.cpp | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/embed.h | 34 +++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 lib/embed.cpp create mode 100644 lib/embed.h (limited to 'lib') diff --git a/lib/embed.cpp b/lib/embed.cpp new file mode 100644 index 0000000..c3b0286 --- /dev/null +++ b/lib/embed.cpp @@ -0,0 +1,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 // 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); +} + diff --git a/lib/embed.h b/lib/embed.h new file mode 100644 index 0000000..566b14c --- /dev/null +++ b/lib/embed.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace embed { + +enum Compression { + None, + Zstd +}; + +struct ResourceData { + Compression compression = None; + std::span dictionary; +}; + +class Resources { +public: + explicit Resources(const ResourceData &info); + ~Resources(); + + [[nodiscard]] + std::span decompress(const std::span &entry); + +private: + const ResourceData m_info; +}; // class + +} + -- cgit v1.2.1