Path: blob/main/sys/contrib/openzfs/module/zstd/lib/decompress/zstd_ddict.c
48774 views
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only1/*2* Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.3* All rights reserved.4*5* This source code is licensed under both the BSD-style license (found in the6* LICENSE file in the root directory of this source tree) and the GPLv2 (found7* in the COPYING file in the root directory of this source tree).8* You may select, at your option, one of the above-listed licenses.9*/1011/* zstd_ddict.c :12* concentrates all logic that needs to know the internals of ZSTD_DDict object */1314/*-*******************************************************15* Dependencies16*********************************************************/17#include <string.h> /* memcpy, memmove, memset */18#include "../common/cpu.h" /* bmi2 */19#include "../common/mem.h" /* low level memory routines */20#define FSE_STATIC_LINKING_ONLY21#include "../common/fse.h"22#define HUF_STATIC_LINKING_ONLY23#include "../common/huf.h"24#include "zstd_decompress_internal.h"25#include "zstd_ddict.h"2627#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)28# include "../legacy/zstd_legacy.h"29#endif30313233/*-*******************************************************34* Types35*********************************************************/36struct ZSTD_DDict_s {37void* dictBuffer;38const void* dictContent;39size_t dictSize;40ZSTD_entropyDTables_t entropy;41U32 dictID;42U32 entropyPresent;43ZSTD_customMem cMem;44}; /* typedef'd to ZSTD_DDict within "zstd.h" */4546const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict)47{48assert(ddict != NULL);49return ddict->dictContent;50}5152size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict)53{54assert(ddict != NULL);55return ddict->dictSize;56}5758void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)59{60DEBUGLOG(4, "ZSTD_copyDDictParameters");61assert(dctx != NULL);62assert(ddict != NULL);63dctx->dictID = ddict->dictID;64dctx->prefixStart = ddict->dictContent;65dctx->virtualStart = ddict->dictContent;66dctx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize;67dctx->previousDstEnd = dctx->dictEnd;68#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION69dctx->dictContentBeginForFuzzing = dctx->prefixStart;70dctx->dictContentEndForFuzzing = dctx->previousDstEnd;71#endif72if (ddict->entropyPresent) {73dctx->litEntropy = 1;74dctx->fseEntropy = 1;75dctx->LLTptr = ddict->entropy.LLTable;76dctx->MLTptr = ddict->entropy.MLTable;77dctx->OFTptr = ddict->entropy.OFTable;78dctx->HUFptr = ddict->entropy.hufTable;79dctx->entropy.rep[0] = ddict->entropy.rep[0];80dctx->entropy.rep[1] = ddict->entropy.rep[1];81dctx->entropy.rep[2] = ddict->entropy.rep[2];82} else {83dctx->litEntropy = 0;84dctx->fseEntropy = 0;85}86}878889static size_t90ZSTD_loadEntropy_intoDDict(ZSTD_DDict* ddict,91ZSTD_dictContentType_e dictContentType)92{93ddict->dictID = 0;94ddict->entropyPresent = 0;95if (dictContentType == ZSTD_dct_rawContent) return 0;9697if (ddict->dictSize < 8) {98if (dictContentType == ZSTD_dct_fullDict)99return ERROR(dictionary_corrupted); /* only accept specified dictionaries */100return 0; /* pure content mode */101}102{ U32 const magic = MEM_readLE32(ddict->dictContent);103if (magic != ZSTD_MAGIC_DICTIONARY) {104if (dictContentType == ZSTD_dct_fullDict)105return ERROR(dictionary_corrupted); /* only accept specified dictionaries */106return 0; /* pure content mode */107}108}109ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_FRAMEIDSIZE);110111/* load entropy tables */112RETURN_ERROR_IF(ZSTD_isError(ZSTD_loadDEntropy(113&ddict->entropy, ddict->dictContent, ddict->dictSize)),114dictionary_corrupted, "");115ddict->entropyPresent = 1;116return 0;117}118119120static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict,121const void* dict, size_t dictSize,122ZSTD_dictLoadMethod_e dictLoadMethod,123ZSTD_dictContentType_e dictContentType)124{125if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dict) || (!dictSize)) {126ddict->dictBuffer = NULL;127ddict->dictContent = dict;128if (!dict) dictSize = 0;129} else {130void* const internalBuffer = ZSTD_malloc(dictSize, ddict->cMem);131ddict->dictBuffer = internalBuffer;132ddict->dictContent = internalBuffer;133if (!internalBuffer) return ERROR(memory_allocation);134memcpy(internalBuffer, dict, dictSize);135}136ddict->dictSize = dictSize;137ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */138139/* parse dictionary content */140FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , "");141142return 0;143}144145ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,146ZSTD_dictLoadMethod_e dictLoadMethod,147ZSTD_dictContentType_e dictContentType,148ZSTD_customMem customMem)149{150if (!customMem.customAlloc ^ !customMem.customFree) return NULL;151152{ ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_malloc(sizeof(ZSTD_DDict), customMem);153if (ddict == NULL) return NULL;154ddict->cMem = customMem;155{ size_t const initResult = ZSTD_initDDict_internal(ddict,156dict, dictSize,157dictLoadMethod, dictContentType);158if (ZSTD_isError(initResult)) {159ZSTD_freeDDict(ddict);160return NULL;161} }162return ddict;163}164}165166/*! ZSTD_createDDict() :167* Create a digested dictionary, to start decompression without startup delay.168* `dict` content is copied inside DDict.169* Consequently, `dict` can be released after `ZSTD_DDict` creation */170ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize)171{172ZSTD_customMem const allocator = { NULL, NULL, NULL };173return ZSTD_createDDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, allocator);174}175176/*! ZSTD_createDDict_byReference() :177* Create a digested dictionary, to start decompression without startup delay.178* Dictionary content is simply referenced, it will be accessed during decompression.179* Warning : dictBuffer must outlive DDict (DDict must be freed before dictBuffer) */180ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize)181{182ZSTD_customMem const allocator = { NULL, NULL, NULL };183return ZSTD_createDDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, allocator);184}185186187const ZSTD_DDict* ZSTD_initStaticDDict(188void* sBuffer, size_t sBufferSize,189const void* dict, size_t dictSize,190ZSTD_dictLoadMethod_e dictLoadMethod,191ZSTD_dictContentType_e dictContentType)192{193size_t const neededSpace = sizeof(ZSTD_DDict)194+ (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);195ZSTD_DDict* const ddict = (ZSTD_DDict*)sBuffer;196assert(sBuffer != NULL);197assert(dict != NULL);198if ((size_t)sBuffer & 7) return NULL; /* 8-aligned */199if (sBufferSize < neededSpace) return NULL;200if (dictLoadMethod == ZSTD_dlm_byCopy) {201memcpy(ddict+1, dict, dictSize); /* local copy */202dict = ddict+1;203}204if (ZSTD_isError( ZSTD_initDDict_internal(ddict,205dict, dictSize,206ZSTD_dlm_byRef, dictContentType) ))207return NULL;208return ddict;209}210211212size_t ZSTD_freeDDict(ZSTD_DDict* ddict)213{214if (ddict==NULL) return 0; /* support free on NULL */215{ ZSTD_customMem const cMem = ddict->cMem;216ZSTD_free(ddict->dictBuffer, cMem);217ZSTD_free(ddict, cMem);218return 0;219}220}221222/*! ZSTD_estimateDDictSize() :223* Estimate amount of memory that will be needed to create a dictionary for decompression.224* Note : dictionary created by reference using ZSTD_dlm_byRef are smaller */225size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod)226{227return sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);228}229230size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict)231{232if (ddict==NULL) return 0; /* support sizeof on NULL */233return sizeof(*ddict) + (ddict->dictBuffer ? ddict->dictSize : 0) ;234}235236/*! ZSTD_getDictID_fromDDict() :237* Provides the dictID of the dictionary loaded into `ddict`.238* If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.239* Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */240unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict)241{242if (ddict==NULL) return 0;243return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize);244}245246247