7634 lines · 329.4 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause/* * Copyright (c) Meta Platforms, Inc. and affiliates. * 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. */ /*-**************************************  Dependencies***************************************/#include "../common/allocations.h"  /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */#include "../common/zstd_deps.h"  /* INT_MAX, ZSTD_memset, ZSTD_memcpy */#include "../common/mem.h"#include "../common/error_private.h"#include "hist.h"           /* HIST_countFast_wksp */#define FSE_STATIC_LINKING_ONLY   /* FSE_encodeSymbol */#include "../common/fse.h"#include "../common/huf.h"#include "zstd_compress_internal.h"#include "zstd_compress_sequences.h"#include "zstd_compress_literals.h"#include "zstd_fast.h"#include "zstd_double_fast.h"#include "zstd_lazy.h"#include "zstd_opt.h"#include "zstd_ldm.h"#include "zstd_compress_superblock.h"#include  "../common/bits.h"      /* ZSTD_highbit32, ZSTD_rotateRight_U64 */ /* ****************************************************************  Tuning parameters*****************************************************************//*! * COMPRESS_HEAPMODE : * Select how default decompression function ZSTD_compress() allocates its context, * on stack (0, default), or into heap (1). * Note that functions with explicit context such as ZSTD_compressCCtx() are unaffected. */ /*! * ZSTD_HASHLOG3_MAX : * Maximum size of the hash table dedicated to find 3-bytes matches, * in log format, aka 17 => 1 << 17 == 128Ki positions. * This structure is only used in zstd_opt. * Since allocation is centralized for all strategies, it has to be known here. * The actual (selected) size of the hash table is then stored in ZSTD_MatchState_t.hashLog3, * so that zstd_opt.c doesn't need to know about this constant. */#ifndef ZSTD_HASHLOG3_MAX#  define ZSTD_HASHLOG3_MAX 17#endif /*-**************************************  Helper functions***************************************//* ZSTD_compressBound() * Note that the result from this function is only valid for * the one-pass compression functions. * When employing the streaming mode, * if flushes are frequently altering the size of blocks, * the overhead from block headers can make the compressed data larger * than the return value of ZSTD_compressBound(). */size_t ZSTD_compressBound(size_t srcSize) {    size_t const r = ZSTD_COMPRESSBOUND(srcSize);    if (r==0) return ERROR(srcSize_wrong);    return r;}  /*-**************************************  Context memory management***************************************/struct ZSTD_CDict_s {    const void* dictContent;    size_t dictContentSize;    ZSTD_dictContentType_e dictContentType; /* The dictContentType the CDict was created with */    U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */    ZSTD_cwksp workspace;    ZSTD_MatchState_t matchState;    ZSTD_compressedBlockState_t cBlockState;    ZSTD_customMem customMem;    U32 dictID;    int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */    ZSTD_ParamSwitch_e useRowMatchFinder; /* Indicates whether the CDict was created with params that would use                                           * row-based matchfinder. Unless the cdict is reloaded, we will use                                           * the same greedy/lazy matchfinder at compression time.                                           */};  /* typedef'd to ZSTD_CDict within "zstd.h" */ ZSTD_CCtx* ZSTD_createCCtx(void){    return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);} static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager){    assert(cctx != NULL);    ZSTD_memset(cctx, 0, sizeof(*cctx));    cctx->customMem = memManager;    cctx->bmi2 = ZSTD_cpuSupportsBmi2();    {   size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters);        assert(!ZSTD_isError(err));        (void)err;    }} ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem){    ZSTD_STATIC_ASSERT(zcss_init==0);    ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));    if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;    {   ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_customMalloc(sizeof(ZSTD_CCtx), customMem);        if (!cctx) return NULL;        ZSTD_initCCtx(cctx, customMem);        return cctx;    }} ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize){    ZSTD_cwksp ws;    ZSTD_CCtx* cctx;    if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL;  /* minimum size */    if ((size_t)workspace & 7) return NULL;  /* must be 8-aligned */    ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc);     cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx));    if (cctx == NULL) return NULL;     ZSTD_memset(cctx, 0, sizeof(ZSTD_CCtx));    ZSTD_cwksp_move(&cctx->workspace, &ws);    cctx->staticSize = workspaceSize;     /* statically sized space. tmpWorkspace never moves (but prev/next block swap places) */    if (!ZSTD_cwksp_check_available(&cctx->workspace, TMP_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL;    cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));    cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));    cctx->tmpWorkspace = ZSTD_cwksp_reserve_object(&cctx->workspace, TMP_WORKSPACE_SIZE);    cctx->tmpWkspSize = TMP_WORKSPACE_SIZE;    cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());    return cctx;} /* * Clears and frees all of the dictionaries in the CCtx. */static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx){    ZSTD_customFree(cctx->localDict.dictBuffer, cctx->customMem);    ZSTD_freeCDict(cctx->localDict.cdict);    ZSTD_memset(&cctx->localDict, 0, sizeof(cctx->localDict));    ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));    cctx->cdict = NULL;} static size_t ZSTD_sizeof_localDict(ZSTD_localDict dict){    size_t const bufferSize = dict.dictBuffer != NULL ? dict.dictSize : 0;    size_t const cdictSize = ZSTD_sizeof_CDict(dict.cdict);    return bufferSize + cdictSize;} static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx){    assert(cctx != NULL);    assert(cctx->staticSize == 0);    ZSTD_clearAllDicts(cctx);    ZSTD_cwksp_free(&cctx->workspace, cctx->customMem);} size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx){    DEBUGLOG(3, "ZSTD_freeCCtx (address: %p)", (void*)cctx);    if (cctx==NULL) return 0;   /* support free on NULL */    RETURN_ERROR_IF(cctx->staticSize, memory_allocation,                    "not compatible with static CCtx");    {   int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx);        ZSTD_freeCCtxContent(cctx);        if (!cctxInWorkspace) ZSTD_customFree(cctx, cctx->customMem);    }    return 0;}  static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx){    (void)cctx;    return 0;}  size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx){    if (cctx==NULL) return 0;   /* support sizeof on NULL */    /* cctx may be in the workspace */    return (cctx->workspace.workspace == cctx ? 0 : sizeof(*cctx))           + ZSTD_cwksp_sizeof(&cctx->workspace)           + ZSTD_sizeof_localDict(cctx->localDict)           + ZSTD_sizeof_mtctx(cctx);} size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs){    return ZSTD_sizeof_CCtx(zcs);  /* same object */} /* private API call, for dictBuilder only */const SeqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } /* Returns true if the strategy supports using a row based matchfinder */static int ZSTD_rowMatchFinderSupported(const ZSTD_strategy strategy) {    return (strategy >= ZSTD_greedy && strategy <= ZSTD_lazy2);} /* Returns true if the strategy and useRowMatchFinder mode indicate that we will use the row based matchfinder * for this compression. */static int ZSTD_rowMatchFinderUsed(const ZSTD_strategy strategy, const ZSTD_ParamSwitch_e mode) {    assert(mode != ZSTD_ps_auto);    return ZSTD_rowMatchFinderSupported(strategy) && (mode == ZSTD_ps_enable);} /* Returns row matchfinder usage given an initial mode and cParams */static ZSTD_ParamSwitch_e ZSTD_resolveRowMatchFinderMode(ZSTD_ParamSwitch_e mode,                                                         const ZSTD_compressionParameters* const cParams) {    /* The Linux Kernel does not use SIMD, and 128KB is a very common size, e.g. in BtrFS.     * The row match finder is slower for this size without SIMD, so disable it.     */    const unsigned kWindowLogLowerBound = 17;    if (mode != ZSTD_ps_auto) return mode; /* if requested enabled, but no SIMD, we still will use row matchfinder */    mode = ZSTD_ps_disable;    if (!ZSTD_rowMatchFinderSupported(cParams->strategy)) return mode;    if (cParams->windowLog > kWindowLogLowerBound) mode = ZSTD_ps_enable;    return mode;} /* Returns block splitter usage (generally speaking, when using slower/stronger compression modes) */static ZSTD_ParamSwitch_e ZSTD_resolveBlockSplitterMode(ZSTD_ParamSwitch_e mode,                                                        const ZSTD_compressionParameters* const cParams) {    if (mode != ZSTD_ps_auto) return mode;    return (cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 17) ? ZSTD_ps_enable : ZSTD_ps_disable;} /* Returns 1 if the arguments indicate that we should allocate a chainTable, 0 otherwise */static int ZSTD_allocateChainTable(const ZSTD_strategy strategy,                                   const ZSTD_ParamSwitch_e useRowMatchFinder,                                   const U32 forDDSDict) {    assert(useRowMatchFinder != ZSTD_ps_auto);    /* We always should allocate a chaintable if we are allocating a matchstate for a DDS dictionary matchstate.     * We do not allocate a chaintable if we are using ZSTD_fast, or are using the row-based matchfinder.     */    return forDDSDict || ((strategy != ZSTD_fast) && !ZSTD_rowMatchFinderUsed(strategy, useRowMatchFinder));} /* Returns ZSTD_ps_enable if compression parameters are such that we should * enable long distance matching (wlog >= 27, strategy >= btopt). * Returns ZSTD_ps_disable otherwise. */static ZSTD_ParamSwitch_e ZSTD_resolveEnableLdm(ZSTD_ParamSwitch_e mode,                                 const ZSTD_compressionParameters* const cParams) {    if (mode != ZSTD_ps_auto) return mode;    return (cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27) ? ZSTD_ps_enable : ZSTD_ps_disable;} static int ZSTD_resolveExternalSequenceValidation(int mode) {    return mode;} /* Resolves maxBlockSize to the default if no value is present. */static size_t ZSTD_resolveMaxBlockSize(size_t maxBlockSize) {    if (maxBlockSize == 0) {        return ZSTD_BLOCKSIZE_MAX;    } else {        return maxBlockSize;    }} static ZSTD_ParamSwitch_e ZSTD_resolveExternalRepcodeSearch(ZSTD_ParamSwitch_e value, int cLevel) {    if (value != ZSTD_ps_auto) return value;    if (cLevel < 10) {        return ZSTD_ps_disable;    } else {        return ZSTD_ps_enable;    }} /* Returns 1 if compression parameters are such that CDict hashtable and chaintable indices are tagged. * If so, the tags need to be removed in ZSTD_resetCCtx_byCopyingCDict. */static int ZSTD_CDictIndicesAreTagged(const ZSTD_compressionParameters* const cParams) {    return cParams->strategy == ZSTD_fast || cParams->strategy == ZSTD_dfast;} static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(        ZSTD_compressionParameters cParams){    ZSTD_CCtx_params cctxParams;    /* should not matter, as all cParams are presumed properly defined */    ZSTD_CCtxParams_init(&cctxParams, ZSTD_CLEVEL_DEFAULT);    cctxParams.cParams = cParams;     /* Adjust advanced params according to cParams */    cctxParams.ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams.ldmParams.enableLdm, &cParams);    if (cctxParams.ldmParams.enableLdm == ZSTD_ps_enable) {        ZSTD_ldm_adjustParameters(&cctxParams.ldmParams, &cParams);        assert(cctxParams.ldmParams.hashLog >= cctxParams.ldmParams.bucketSizeLog);        assert(cctxParams.ldmParams.hashRateLog < 32);    }    cctxParams.postBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams.postBlockSplitter, &cParams);    cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams);    cctxParams.validateSequences = ZSTD_resolveExternalSequenceValidation(cctxParams.validateSequences);    cctxParams.maxBlockSize = ZSTD_resolveMaxBlockSize(cctxParams.maxBlockSize);    cctxParams.searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(cctxParams.searchForExternalRepcodes,                                                                             cctxParams.compressionLevel);    assert(!ZSTD_checkCParams(cParams));    return cctxParams;} static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(        ZSTD_customMem customMem){    ZSTD_CCtx_params* params;    if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;    params = (ZSTD_CCtx_params*)ZSTD_customCalloc(            sizeof(ZSTD_CCtx_params), customMem);    if (!params) { return NULL; }    ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);    params->customMem = customMem;    return params;} ZSTD_CCtx_params* ZSTD_createCCtxParams(void){    return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem);} size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params){    if (params == NULL) { return 0; }    ZSTD_customFree(params, params->customMem);    return 0;} size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params){    return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);} size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) {    RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");    ZSTD_memset(cctxParams, 0, sizeof(*cctxParams));    cctxParams->compressionLevel = compressionLevel;    cctxParams->fParams.contentSizeFlag = 1;    return 0;} #define ZSTD_NO_CLEVEL 0 /* * Initializes `cctxParams` from `params` and `compressionLevel`. * @param compressionLevel If params are derived from a compression level then that compression level, otherwise ZSTD_NO_CLEVEL. */static voidZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams,                        const ZSTD_parameters* params,                              int compressionLevel){    assert(!ZSTD_checkCParams(params->cParams));    ZSTD_memset(cctxParams, 0, sizeof(*cctxParams));    cctxParams->cParams = params->cParams;    cctxParams->fParams = params->fParams;    /* Should not matter, as all cParams are presumed properly defined.     * But, set it for tracing anyway.     */    cctxParams->compressionLevel = compressionLevel;    cctxParams->useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams->useRowMatchFinder, &params->cParams);    cctxParams->postBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams->postBlockSplitter, &params->cParams);    cctxParams->ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams->ldmParams.enableLdm, &params->cParams);    cctxParams->validateSequences = ZSTD_resolveExternalSequenceValidation(cctxParams->validateSequences);    cctxParams->maxBlockSize = ZSTD_resolveMaxBlockSize(cctxParams->maxBlockSize);    cctxParams->searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(cctxParams->searchForExternalRepcodes, compressionLevel);    DEBUGLOG(4, "ZSTD_CCtxParams_init_internal: useRowMatchFinder=%d, useBlockSplitter=%d ldm=%d",                cctxParams->useRowMatchFinder, cctxParams->postBlockSplitter, cctxParams->ldmParams.enableLdm);} size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params){    RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");    FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");    ZSTD_CCtxParams_init_internal(cctxParams, &params, ZSTD_NO_CLEVEL);    return 0;} /* * Sets cctxParams' cParams and fParams from params, but otherwise leaves them alone. * @param params Validated zstd parameters. */static void ZSTD_CCtxParams_setZstdParams(        ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params){    assert(!ZSTD_checkCParams(params->cParams));    cctxParams->cParams = params->cParams;    cctxParams->fParams = params->fParams;    /* Should not matter, as all cParams are presumed properly defined.     * But, set it for tracing anyway.     */    cctxParams->compressionLevel = ZSTD_NO_CLEVEL;} ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param){    ZSTD_bounds bounds = { 0, 0, 0 };     switch(param)    {    case ZSTD_c_compressionLevel:        bounds.lowerBound = ZSTD_minCLevel();        bounds.upperBound = ZSTD_maxCLevel();        return bounds;     case ZSTD_c_windowLog:        bounds.lowerBound = ZSTD_WINDOWLOG_MIN;        bounds.upperBound = ZSTD_WINDOWLOG_MAX;        return bounds;     case ZSTD_c_hashLog:        bounds.lowerBound = ZSTD_HASHLOG_MIN;        bounds.upperBound = ZSTD_HASHLOG_MAX;        return bounds;     case ZSTD_c_chainLog:        bounds.lowerBound = ZSTD_CHAINLOG_MIN;        bounds.upperBound = ZSTD_CHAINLOG_MAX;        return bounds;     case ZSTD_c_searchLog:        bounds.lowerBound = ZSTD_SEARCHLOG_MIN;        bounds.upperBound = ZSTD_SEARCHLOG_MAX;        return bounds;     case ZSTD_c_minMatch:        bounds.lowerBound = ZSTD_MINMATCH_MIN;        bounds.upperBound = ZSTD_MINMATCH_MAX;        return bounds;     case ZSTD_c_targetLength:        bounds.lowerBound = ZSTD_TARGETLENGTH_MIN;        bounds.upperBound = ZSTD_TARGETLENGTH_MAX;        return bounds;     case ZSTD_c_strategy:        bounds.lowerBound = ZSTD_STRATEGY_MIN;        bounds.upperBound = ZSTD_STRATEGY_MAX;        return bounds;     case ZSTD_c_contentSizeFlag:        bounds.lowerBound = 0;        bounds.upperBound = 1;        return bounds;     case ZSTD_c_checksumFlag:        bounds.lowerBound = 0;        bounds.upperBound = 1;        return bounds;     case ZSTD_c_dictIDFlag:        bounds.lowerBound = 0;        bounds.upperBound = 1;        return bounds;     case ZSTD_c_nbWorkers:        bounds.lowerBound = 0;        bounds.upperBound = 0;        return bounds;     case ZSTD_c_jobSize:        bounds.lowerBound = 0;        bounds.upperBound = 0;        return bounds;     case ZSTD_c_overlapLog:        bounds.lowerBound = 0;        bounds.upperBound = 0;        return bounds;     case ZSTD_c_enableDedicatedDictSearch:        bounds.lowerBound = 0;        bounds.upperBound = 1;        return bounds;     case ZSTD_c_enableLongDistanceMatching:        bounds.lowerBound = (int)ZSTD_ps_auto;        bounds.upperBound = (int)ZSTD_ps_disable;        return bounds;     case ZSTD_c_ldmHashLog:

Lines 1–500 of 7634.