From 699f11b4f726c258e4589a446eb16428550e7e8c Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Thu, 17 Aug 2017 17:33:46 -0700 Subject: [PATCH 001/248] Create opaque parameter structure --- lib/common/zstd_internal.h | 4 +++ lib/compress/zstd_compress.c | 52 ++++++++++++++++++++++++++---------- lib/zstd.h | 2 ++ 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 1621bca61..ddafc7874 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -221,6 +221,10 @@ typedef struct seqDef_s { U16 matchLength; } seqDef; +typedef struct ZSTD_CCtx_params_s { + ZSTD_compressionParameters cParams; + ZSTD_frameParameters fParams; +} ZSTD_CCtx_params; typedef struct { seqDef* sequencesStart; diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 998fb3d49..3de173a62 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -84,8 +84,8 @@ struct ZSTD_CCtx_s { ZSTD_compressionStage_e stage; U32 dictID; int compressionLevel; - ZSTD_parameters requestedParams; - ZSTD_parameters appliedParams; + ZSTD_CCtx_params requestedParams; + ZSTD_CCtx_params appliedParams; void* workSpace; size_t workSpaceSize; size_t blockSize; @@ -202,7 +202,28 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) /* private API call, for dictBuilder only */ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } -static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { return cctx->appliedParams; } +// TODO: get rid of this function +static ZSTD_parameters ZSTD_getParamsFromCCtxParams(const ZSTD_CCtx_params cctxParams) +{ + ZSTD_parameters params; + params.cParams = cctxParams.cParams; + params.fParams = cctxParams.fParams; + return params; +} + +// TODO: get rid of this function too +static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromParams(ZSTD_parameters params) { + ZSTD_CCtx_params cctxParams; + memset(&cctxParams, 0, sizeof(ZSTD_CCtx_params)); + cctxParams.cParams = params.cParams; + cctxParams.fParams = params.fParams; + return cctxParams; +} + + +static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { + return ZSTD_getParamsFromCCtxParams(cctx->appliedParams); +} /* older variant; will be deprecated */ size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value) @@ -582,7 +603,7 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 ple { U32 const end = (U32)(cctx->nextSrc - cctx->base); DEBUGLOG(5, "continue mode"); - cctx->appliedParams = params; + cctx->appliedParams = ZSTD_makeCCtxParamsFromParams(params); cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; cctx->consumedSrcSize = 0; if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) @@ -670,7 +691,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, } } /* init params */ - zc->appliedParams = params; + zc->appliedParams = ZSTD_makeCCtxParamsFromParams(params); zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; zc->consumedSrcSize = 0; if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) @@ -766,7 +787,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong); memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); - { ZSTD_parameters params = srcCCtx->appliedParams; + { ZSTD_parameters params = ZSTD_getParamsFromCCtxParams(srcCCtx->appliedParams); params.fParams = fParams; ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, ZSTDcrp_noMemset, zbuff); @@ -2952,8 +2973,10 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */ if (frame && (cctx->stage==ZSTDcs_init)) { - fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, - cctx->pledgedSrcSizePlusOne-1, cctx->dictID); + fhSize = ZSTD_writeFrameHeader( + dst, dstCapacity, + ZSTD_getParamsFromCCtxParams(cctx->appliedParams), + cctx->pledgedSrcSizePlusOne-1, cctx->dictID); if (ZSTD_isError(fhSize)) return fhSize; dstCapacity -= fhSize; dst = (char*)dst + fhSize; @@ -3269,7 +3292,7 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) /* special case : empty frame */ if (cctx->stage == ZSTDcs_init) { - fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0); + fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, ZSTD_getParamsFromCCtxParams(cctx->appliedParams), 0, 0); if (ZSTD_isError(fhSize)) return fhSize; dstCapacity -= fhSize; op += fhSize; @@ -3545,7 +3568,8 @@ size_t ZSTD_compressBegin_usingCDict_advanced( ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) { if (cdict==NULL) return ERROR(dictionary_wrong); - { ZSTD_parameters params = cdict->refContext->appliedParams; + { ZSTD_parameters params = + ZSTD_getParamsFromCCtxParams(cdict->refContext->appliedParams); params.fParams = fParams; DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced"); return ZSTD_compressBegin_internal(cctx, @@ -3653,7 +3677,7 @@ static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) { - ZSTD_parameters params = zcs->requestedParams; + ZSTD_parameters params = ZSTD_getParamsFromCCtxParams(zcs->requestedParams); params.fParams.contentSizeFlag = (pledgedSrcSize > 0); DEBUGLOG(5, "ZSTD_resetCStream"); if (zcs->compressionLevel != ZSTD_CLEVEL_CUSTOM) { @@ -3696,7 +3720,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, zcs->cdict = cdict; } - zcs->requestedParams = params; + zcs->requestedParams = ZSTD_makeCCtxParamsFromParams(params); zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM; return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->dictMode, zcs->cdict, params, pledgedSrcSize); } @@ -3729,7 +3753,7 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, ZSTD_parameters params, unsigned long long pledgedSrcSize) { CHECK_F( ZSTD_checkCParams(params.cParams) ); - zcs->requestedParams = params; + zcs->requestedParams = ZSTD_makeCCtxParamsFromParams(params); zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM; return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, pledgedSrcSize); } @@ -3943,7 +3967,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, if (cctx->streamStage == zcss_init) { const void* const prefix = cctx->prefix; size_t const prefixSize = cctx->prefixSize; - ZSTD_parameters params = cctx->requestedParams; + ZSTD_parameters params = ZSTD_getParamsFromCCtxParams(cctx->requestedParams); if (cctx->compressionLevel != ZSTD_CLEVEL_CUSTOM) params.cParams = ZSTD_getCParams(cctx->compressionLevel, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); diff --git a/lib/zstd.h b/lib/zstd.h index a2a756dfc..4b2f4a3b3 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -425,6 +425,8 @@ typedef struct { ZSTD_frameParameters fParams; } ZSTD_parameters; +typedef struct ZSTD_CCtx_params_s ZSTD_CCtx_params; + /*= Custom memory allocation functions */ typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size); typedef void (*ZSTD_freeFunction) (void* opaque, void* address); From ade95b8bed67c48b8bd91f0503904ea93af8dcd0 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Thu, 17 Aug 2017 18:13:08 -0700 Subject: [PATCH 002/248] Add opaque interfaces for static initialization --- lib/compress/zstd_compress.c | 150 ++++++++++++++++++++++++----------- lib/zstd.h | 9 +++ 2 files changed, 111 insertions(+), 48 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 3de173a62..b5bdf680e 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -220,6 +220,16 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromParams(ZSTD_parameters params) { return cctxParams; } +// TODO: get rid of this function too +static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( + ZSTD_compressionParameters cParams) +{ + ZSTD_CCtx_params cctxParams; + memset(&cctxParams, 0, sizeof(ZSTD_CCtx_params)); + cctxParams.cParams = cParams; + return cctxParams; +} + static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { return ZSTD_getParamsFromCCtxParams(cctx->appliedParams); @@ -537,29 +547,40 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); } +size_t ZSTD_estimateCCtxSize_advanced_opaque(ZSTD_CCtx_params* params) +{ + if (params == NULL) { return 0; } + { ZSTD_compressionParameters cParams = params->cParams; + size_t const blockSize = + MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); + U32 const divider = (cParams.searchLength==3) ? 3 : 4; + size_t const maxNbSeq = blockSize / divider; + size_t const tokenSpace = blockSize + 11*maxNbSeq; + size_t const chainSize = + (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog); + size_t const hSize = ((size_t)1) << cParams.hashLog; + U32 const hashLog3 = (cParams.searchLength>3) ? + 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog); + size_t const h3Size = ((size_t)1) << hashLog3; + size_t const entropySpace = sizeof(ZSTD_entropyCTables_t); + size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); + + size_t const optBudget = + ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog); - size_t const h3Size = ((size_t)1) << hashLog3; - size_t const entropySpace = sizeof(ZSTD_entropyCTables_t); - size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); - - size_t const optBudget = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<cParams; + size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced(cParams); + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); + size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize; + size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; + size_t const streamingSize = inBuffSize + outBuffSize; + + return CCtxSize + streamingSize; + } +} + size_t ZSTD_estimateCStreamSize_advanced(ZSTD_compressionParameters cParams) { - size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced(cParams); - size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); - size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize; - size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; - size_t const streamingSize = inBuffSize + outBuffSize; - - return CCtxSize + streamingSize; + ZSTD_CCtx_params params = ZSTD_makeCCtxParamsFromCParams(cParams); + return ZSTD_estimateCStreamSize_advanced_opaque(¶ms); } size_t ZSTD_estimateCStreamSize(int compressionLevel) { @@ -3390,14 +3421,24 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcS /* ===== Dictionary API ===== */ +size_t ZSTD_estimateCDictSize_advanced_opaque( + size_t dictSize, ZSTD_CCtx_params* params, unsigned byReference) +{ + if (params == NULL) { return 0; } + DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict)); + DEBUGLOG(5, "CCtx estimate : %u", + (U32)ZSTD_estimateCCtxSize_advanced_opaque(params)); + return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced_opaque(params) + + (byReference ? 0 : dictSize); + +} + /*! ZSTD_estimateCDictSize_advanced() : * Estimate amount of memory that will be needed to create a dictionary with following arguments */ size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference) { - DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict)); - DEBUGLOG(5, "CCtx estimate : %u", (U32)ZSTD_estimateCCtxSize_advanced(cParams)); - return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced(cParams) - + (byReference ? 0 : dictSize); + ZSTD_CCtx_params params = ZSTD_makeCCtxParamsFromCParams(cParams); + return ZSTD_estimateCDictSize_advanced_opaque(dictSize, ¶ms, byReference); } size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) @@ -3510,24 +3551,12 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict) } } -/*! ZSTD_initStaticCDict_advanced() : - * Generate a digested dictionary in provided memory area. - * workspace: The memory area to emplace the dictionary into. - * Provided pointer must 8-bytes aligned. - * It must outlive dictionary usage. - * workspaceSize: Use ZSTD_estimateCDictSize() - * to determine how large workspace must be. - * cParams : use ZSTD_getCParams() to transform a compression level - * into its relevants cParams. - * @return : pointer to ZSTD_CDict*, or NULL if error (size too small) - * Note : there is no corresponding "free" function. - * Since workspace was allocated externally, it must be freed externally. - */ -ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, - const void* dict, size_t dictSize, - unsigned byReference, ZSTD_dictMode_e dictMode, - ZSTD_compressionParameters cParams) +ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( + void *workspace, size_t workspaceSize, const void* dict, + size_t dictSize, unsigned byReference, ZSTD_dictMode_e dictMode, + ZSTD_CCtx_params* params) { + ZSTD_compressionParameters cParams = params->cParams; size_t const cctxSize = ZSTD_estimateCCtxSize_advanced(cParams); size_t const neededSize = sizeof(ZSTD_CDict) + (byReference ? 0 : dictSize) + cctxSize; @@ -3557,6 +3586,31 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, return cdict; } +/*! ZSTD_initStaticCDict_advanced() : + * Generate a digested dictionary in provided memory area. + * workspace: The memory area to emplace the dictionary into. + * Provided pointer must 8-bytes aligned. + * It must outlive dictionary usage. + * workspaceSize: Use ZSTD_estimateCDictSize() + * to determine how large workspace must be. + * cParams : use ZSTD_getCParams() to transform a compression level + * into its relevants cParams. + * @return : pointer to ZSTD_CDict*, or NULL if error (size too small) + * Note : there is no corresponding "free" function. + * Since workspace was allocated externally, it must be freed externally. + */ +ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + unsigned byReference, ZSTD_dictMode_e dictMode, + ZSTD_compressionParameters cParams) +{ + ZSTD_CCtx_params params = ZSTD_makeCCtxParamsFromCParams(cParams); + return ZSTD_initStaticCDict_advanced_opaque( + workspace, workspaceSize, dict, dictSize, + byReference, dictMode, ¶ms); +} + + ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) { return ZSTD_getParamsFromCCtx(cdict->refContext); } diff --git a/lib/zstd.h b/lib/zstd.h index 4b2f4a3b3..2111c9de0 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -501,6 +501,7 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); * Note : CCtx estimation is only correct for single-threaded compression */ ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced(ZSTD_compressionParameters cParams); +ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced_opaque(ZSTD_CCtx_params* params); ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); /*! ZSTD_estimate?StreamSize() : @@ -517,6 +518,7 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); * In this case, get total size by adding ZSTD_estimate?DictSize */ ZSTDLIB_API size_t ZSTD_estimateCStreamSize(int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced(ZSTD_compressionParameters cParams); +ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced_opaque(ZSTD_CCtx_params* params); ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize); ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); @@ -526,6 +528,7 @@ ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t sr * Note : dictionary created "byReference" are smaller */ ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference); +ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced_opaque(size_t dictSize, ZSTD_CCtx_params* params, unsigned byReference); ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference); @@ -602,6 +605,12 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict( unsigned byReference, ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams); +ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( + void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + unsigned byReference, ZSTD_dictMode_e dictMode, + ZSTD_CCtx_params* params); + /*! ZSTD_getCParams() : * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. * `estimatedSrcSize` value is optional, select 0 if not known */ From 4169f49171a6fa98baf5e62c5ff6aeb74d675fd9 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Thu, 17 Aug 2017 18:45:04 -0700 Subject: [PATCH 003/248] Add initialization/allocation functions for opaque params --- lib/compress/zstd_compress.c | 38 ++++++++++++++++++++++++++++++++++++ lib/zstd.h | 6 ++++++ 2 files changed, 44 insertions(+) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index b5bdf680e..509f8bedc 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -230,6 +230,44 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( return cctxParams; } +ZSTD_CCtx_params* ZSTD_createCCtxParams(void) +{ + ZSTD_CCtx_params* params = + (ZSTD_CCtx_params*)ZSTD_calloc(sizeof(ZSTD_CCtx_params), + ZSTD_defaultCMem); + if (!params) { return NULL; } + // TODO +// params->compressionLevel = ZSTD_CLEVEL_DEFAULT; + return params; +} + +size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* params, + ZSTD_compressionParameters cParams) +{ + CHECK_F( params == NULL ); + memset(params, 0, sizeof(ZSTD_CCtx_params)); + params->cParams = cParams; + return 0; +} + +ZSTD_CCtx_params* ZSTD_createAndInitCCtxParams( + int compressionLevel, unsigned long long estimatedSrcSize, + size_t dictSize) +{ + ZSTD_CCtx_params* params = ZSTD_createCCtxParams(); + if (params == NULL) { return NULL; } + ZSTD_initCCtxParams(params, ZSTD_getCParams( + compressionLevel, estimatedSrcSize, dictSize)); + return params; +} + +size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) +{ + ZSTD_free(params, ZSTD_defaultCMem); + return 0; +} + + static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { return ZSTD_getParamsFromCCtxParams(cctx->appliedParams); diff --git a/lib/zstd.h b/lib/zstd.h index 2111c9de0..b847d01f2 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -611,6 +611,12 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( unsigned byReference, ZSTD_dictMode_e dictMode, ZSTD_CCtx_params* params); +ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); +ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createAndInitCCtxParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); +ZSTDLIB_API size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* params, ZSTD_compressionParameters cParams); +ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); + + /*! ZSTD_getCParams() : * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. * `estimatedSrcSize` value is optional, select 0 if not known */ From c0221124d5344bcfe727c23fae22cdd506915da6 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Thu, 17 Aug 2017 19:30:22 -0700 Subject: [PATCH 004/248] Add function to set opaque parameters --- lib/common/zstd_internal.h | 2 + lib/compress/zstd_compress.c | 189 +++++++++++++++++++++++++++-------- lib/zstd.h | 4 + 3 files changed, 156 insertions(+), 39 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index ddafc7874..7c806b87c 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -224,6 +224,8 @@ typedef struct seqDef_s { typedef struct ZSTD_CCtx_params_s { ZSTD_compressionParameters cParams; ZSTD_frameParameters fParams; + int compressionLevel; + } ZSTD_CCtx_params; typedef struct { diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 509f8bedc..a48184153 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -230,45 +230,6 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( return cctxParams; } -ZSTD_CCtx_params* ZSTD_createCCtxParams(void) -{ - ZSTD_CCtx_params* params = - (ZSTD_CCtx_params*)ZSTD_calloc(sizeof(ZSTD_CCtx_params), - ZSTD_defaultCMem); - if (!params) { return NULL; } - // TODO -// params->compressionLevel = ZSTD_CLEVEL_DEFAULT; - return params; -} - -size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* params, - ZSTD_compressionParameters cParams) -{ - CHECK_F( params == NULL ); - memset(params, 0, sizeof(ZSTD_CCtx_params)); - params->cParams = cParams; - return 0; -} - -ZSTD_CCtx_params* ZSTD_createAndInitCCtxParams( - int compressionLevel, unsigned long long estimatedSrcSize, - size_t dictSize) -{ - ZSTD_CCtx_params* params = ZSTD_createCCtxParams(); - if (params == NULL) { return NULL; } - ZSTD_initCCtxParams(params, ZSTD_getCParams( - compressionLevel, estimatedSrcSize, dictSize)); - return params; -} - -size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) -{ - ZSTD_free(params, ZSTD_defaultCMem); - return 0; -} - - - static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { return ZSTD_getParamsFromCCtxParams(cctx->appliedParams); } @@ -296,6 +257,55 @@ static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx) cctx->compressionLevel = ZSTD_CLEVEL_CUSTOM; } +ZSTD_CCtx_params* ZSTD_createCCtxParams(void) +{ + ZSTD_CCtx_params* params = + (ZSTD_CCtx_params*)ZSTD_calloc(sizeof(ZSTD_CCtx_params), + ZSTD_defaultCMem); + if (!params) { return NULL; } + params->compressionLevel = ZSTD_CLEVEL_DEFAULT; + return params; +} + +size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* params, + ZSTD_compressionParameters cParams) +{ + memset(params, 0, sizeof(ZSTD_CCtx_params)); + params->cParams = cParams; + params->compressionLevel = ZSTD_CLEVEL_CUSTOM; + return 0; +} + +ZSTD_CCtx_params* ZSTD_createAndInitCCtxParams( + int compressionLevel, unsigned long long estimatedSrcSize, + size_t dictSize) +{ + ZSTD_CCtx_params* params = ZSTD_createCCtxParams(); + if (params == NULL) { return NULL; } + ZSTD_initCCtxParams(params, ZSTD_getCParams( + compressionLevel, estimatedSrcSize, dictSize)); + params->compressionLevel = compressionLevel; + return params; +} + +size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) +{ + if (params == NULL) { return 0; } + ZSTD_free(params, ZSTD_defaultCMem); + return 0; +} + + + +static void ZSTD_cLevelToCCtxParams(ZSTD_CCtx_params* params) +{ + if (params->compressionLevel == ZSTD_CLEVEL_CUSTOM) return; + // TODO: src size, code duplication + params->cParams = ZSTD_getCParams(params->compressionLevel, 0, 0); + params->compressionLevel = ZSTD_CLEVEL_CUSTOM; + +} + #define CLAMPCHECK(val,min,max) { \ if (((val)<(min)) | ((val)>(max))) { \ return ERROR(parameter_outOfBound); \ @@ -443,6 +453,107 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v } } +size_t ZSTD_CCtxParam_setParameter( + ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value) +{ + switch(param) + { + case ZSTD_p_compressionLevel : + if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel(); + if (value == 0) return 0; + params->compressionLevel = value; + return 0; + + case ZSTD_p_windowLog : + if (value == 0) return 0; + CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); + ZSTD_cLevelToCCtxParams(params); + params->cParams.windowLog = value; + return 0; + + case ZSTD_p_hashLog : + if (value == 0) return 0; + CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); + ZSTD_cLevelToCCtxParams(params); + params->cParams.hashLog = value; + return 0; + + case ZSTD_p_chainLog : + if (value == 0) return 0; + CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); + ZSTD_cLevelToCCtxParams(params); + params->cParams.chainLog = value; + return 0; + + case ZSTD_p_searchLog : + if (value == 0) return 0; + CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); + ZSTD_cLevelToCCtxParams(params); + params->cParams.searchLog = value; + return 0; + + case ZSTD_p_minMatch : + if (value == 0) return 0; + CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); + ZSTD_cLevelToCCtxParams(params); + params->cParams.searchLength = value; + return 0; + + case ZSTD_p_targetLength : + if (value == 0) return 0; + CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); + ZSTD_cLevelToCCtxParams(params); + params->cParams.targetLength = value; + return 0; + + case ZSTD_p_compressionStrategy : + if (value == 0) return 0; + CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra); + ZSTD_cLevelToCCtxParams(params); + params->cParams.strategy = (ZSTD_strategy)value; + return 0; + + case ZSTD_p_contentSizeFlag : + params->fParams.contentSizeFlag = value > 0; + return 0; + + case ZSTD_p_checksumFlag : + params->fParams.checksumFlag = value > 0; + return 0; + + case ZSTD_p_dictIDFlag : + params->fParams.noDictIDFlag = (value == 0); + return 0; + + case ZSTD_p_dictMode : + ZSTD_STATIC_ASSERT((U32)ZSTD_dm_fullDict > (U32)ZSTD_dm_rawContent); + if (value > (unsigned)ZSTD_dm_fullDict) { + return ERROR(parameter_outOfBound); + } +// cctx->dictMode = (ZSTD_dictMode_e)value; + return 0; + + case ZSTD_p_refDictContent : +// cctx->dictContentByRef = value > 0; + return 0; + + case ZSTD_p_forceMaxWindow : +// cctx->forceWindow = value > 0; + return 0; + + case ZSTD_p_nbThreads : + return 0; + + case ZSTD_p_jobSize : + return 0; + + case ZSTD_p_overlapSizeLog : + return 0; + + default: return ERROR(parameter_unsupported); + } +} + ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) { DEBUGLOG(5, " setting pledgedSrcSize to %u", (U32)pledgedSrcSize); diff --git a/lib/zstd.h b/lib/zstd.h index b847d01f2..e428319d4 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -616,6 +616,8 @@ ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createAndInitCCtxParams(int compressionLevel, ZSTDLIB_API size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* params, ZSTD_compressionParameters cParams); ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); +ZSTDLIB_API + /*! ZSTD_getCParams() : * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. @@ -1009,6 +1011,8 @@ typedef enum { * @result : 0, or an error code (which can be tested with ZSTD_isError()). */ ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value); +ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value); + /*! ZSTD_CCtx_setPledgedSrcSize() : * Total input data size to be compressed as a single frame. * This value will be controlled at the end, and result in error if not respected. From 97e27affcbe26f89b52f16b1a1a0b5e8f924419a Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 18 Aug 2017 11:20:08 -0700 Subject: [PATCH 005/248] Move compression level to cctx params --- lib/compress/zstd_compress.c | 97 +++++++++++++++++++++++------------- lib/zstd.h | 2 + 2 files changed, 64 insertions(+), 35 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index a48184153..1ffeb5565 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -83,7 +83,7 @@ struct ZSTD_CCtx_s { U32 forceWindow; /* force back-references to respect limit of 1<customMem = customMem; - cctx->compressionLevel = ZSTD_CLEVEL_DEFAULT; + cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; ZSTD_STATIC_ASSERT(zcss_init==0); ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1)); return cctx; @@ -230,6 +230,7 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( return cctxParams; } +// TODO: get rid of this function static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { return ZSTD_getParamsFromCCtxParams(cctx->appliedParams); } @@ -251,10 +252,11 @@ size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned #define ZSTD_CLEVEL_CUSTOM 999 static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx) { - if (cctx->compressionLevel==ZSTD_CLEVEL_CUSTOM) return; - cctx->requestedParams.cParams = ZSTD_getCParams(cctx->compressionLevel, - cctx->pledgedSrcSizePlusOne-1, 0); - cctx->compressionLevel = ZSTD_CLEVEL_CUSTOM; + if (cctx->requestedParams.compressionLevel==ZSTD_CLEVEL_CUSTOM) return; + cctx->requestedParams.cParams = + ZSTD_getCParams(cctx->requestedParams.compressionLevel, + cctx->pledgedSrcSizePlusOne-1, 0); + cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; } ZSTD_CCtx_params* ZSTD_createCCtxParams(void) @@ -321,7 +323,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel(); /* cap max compression level */ if (value == 0) return 0; /* special value : 0 means "don't change anything" */ if (cctx->cdict) return ERROR(stage_wrong); - cctx->compressionLevel = value; + cctx->requestedParams.compressionLevel = value; return 0; case ZSTD_p_windowLog : @@ -554,6 +556,13 @@ size_t ZSTD_CCtxParam_setParameter( } } +ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, ZSTD_CCtx_params* params) +{ + (void)cctx; + (void)params; + return 0; +} + ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) { DEBUGLOG(5, " setting pledgedSrcSize to %u", (U32)pledgedSrcSize); @@ -573,9 +582,9 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, s cctx->cdict = NULL; } else { ZSTD_compressionParameters const cParams = - cctx->compressionLevel == ZSTD_CLEVEL_CUSTOM ? + cctx->requestedParams.compressionLevel == ZSTD_CLEVEL_CUSTOM ? cctx->requestedParams.cParams : - ZSTD_getCParams(cctx->compressionLevel, 0, dictSize); + ZSTD_getCParams(cctx->requestedParams.compressionLevel, 0, dictSize); cctx->cdictLocal = ZSTD_createCDict_advanced( dict, dictSize, cctx->dictContentByRef, cctx->dictMode, @@ -779,11 +788,11 @@ static U32 ZSTD_equivalentParams(ZSTD_compressionParameters cParams1, /*! ZSTD_continueCCtx() : * reuse CCtx without reset (note : requires no dictionary) */ -static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 pledgedSrcSize) +static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize) { U32 const end = (U32)(cctx->nextSrc - cctx->base); DEBUGLOG(5, "continue mode"); - cctx->appliedParams = ZSTD_makeCCtxParamsFromParams(params); + cctx->appliedParams = params; cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; cctx->consumedSrcSize = 0; if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) @@ -808,7 +817,7 @@ typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e; /*! ZSTD_resetCCtx_internal() : note : `params` are assumed fully validated at this stage */ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, - ZSTD_parameters params, U64 pledgedSrcSize, + ZSTD_CCtx_params params, U64 pledgedSrcSize, ZSTD_compResetPolicy_e const crp, ZSTD_buffered_policy_e const zbuff) { @@ -871,7 +880,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, } } /* init params */ - zc->appliedParams = ZSTD_makeCCtxParamsFromParams(params); + zc->appliedParams = params; zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; zc->consumedSrcSize = 0; if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) @@ -967,7 +976,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong); memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); - { ZSTD_parameters params = ZSTD_getParamsFromCCtxParams(srcCCtx->appliedParams); + { ZSTD_CCtx_params params = srcCCtx->appliedParams; params.fParams = fParams; ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, ZSTDcrp_noMemset, zbuff); @@ -3100,7 +3109,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, - ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID) + ZSTD_CCtx_params params, U64 pledgedSrcSize, U32 dictID) { BYTE* const op = (BYTE*)dst; U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */ U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */ @@ -3155,7 +3164,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, if (frame && (cctx->stage==ZSTDcs_init)) { fhSize = ZSTD_writeFrameHeader( dst, dstCapacity, - ZSTD_getParamsFromCCtxParams(cctx->appliedParams), + cctx->appliedParams, cctx->pledgedSrcSizePlusOne-1, cctx->dictID); if (ZSTD_isError(fhSize)) return fhSize; dstCapacity -= fhSize; @@ -3206,7 +3215,8 @@ size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) { - U32 const cLevel = cctx->compressionLevel; + // TODO: Applied params compression level okay? Gets overwritten + U32 const cLevel = cctx->appliedParams.compressionLevel; ZSTD_compressionParameters cParams = (cLevel == ZSTD_CLEVEL_CUSTOM) ? cctx->appliedParams.cParams : ZSTD_getCParams(cLevel, 0, 0); @@ -3409,7 +3419,7 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, const ZSTD_CDict* cdict, - ZSTD_parameters params, U64 pledgedSrcSize, + ZSTD_CCtx_params params, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { DEBUGLOG(4, "ZSTD_compressBegin_internal"); @@ -3437,18 +3447,21 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize) { + + ZSTD_CCtx_params cctxParams = cctx->requestedParams; + cctxParams.cParams = params.cParams; + cctxParams.fParams = params.fParams; /* compression parameters verification and optimization */ CHECK_F(ZSTD_checkCParams(params.cParams)); return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL, - params, pledgedSrcSize, ZSTDb_not_buffered); + cctxParams, pledgedSrcSize, ZSTDb_not_buffered); } size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) { ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); - return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL, - params, 0, ZSTDb_not_buffered); + return ZSTD_compressBegin_advanced(cctx, dict, dictSize, params, 0); } @@ -3472,7 +3485,7 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) /* special case : empty frame */ if (cctx->stage == ZSTDcs_init) { - fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, ZSTD_getParamsFromCCtxParams(cctx->appliedParams), 0, 0); + fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0); if (ZSTD_isError(fhSize)) return fhSize; dstCapacity -= fhSize; op += fhSize; @@ -3528,8 +3541,12 @@ static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, const void* dict,size_t dictSize, ZSTD_parameters params) { + ZSTD_CCtx_params cctxParams = cctx->requestedParams; + cctxParams.cParams = params.cParams; + cctxParams.fParams = params.fParams; + CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL, - params, srcSize, ZSTDb_not_buffered) ); + cctxParams, srcSize, ZSTDb_not_buffered) ); return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); } @@ -3634,10 +3651,14 @@ static size_t ZSTD_initCDict_internal( { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */ ZSTD_parameters const params = ZSTD_makeParams(cParams, fParams); + ZSTD_CCtx_params cctxParams = + ZSTD_makeCCtxParamsFromParams(params); + cctxParams.compressionLevel = + cdict->refContext->requestedParams.compressionLevel; CHECK_F( ZSTD_compressBegin_internal(cdict->refContext, cdict->dictContent, dictSize, dictMode, NULL, - params, ZSTD_CONTENTSIZE_UNKNOWN, + cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered) ); } @@ -3764,6 +3785,10 @@ ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) { return ZSTD_getParamsFromCCtx(cdict->refContext); } +static ZSTD_CCtx_params ZSTD_getCCtxParamsFromCDict(const ZSTD_CDict* cdict) { + return cdict->refContext->appliedParams; +} + /* ZSTD_compressBegin_usingCDict_advanced() : * cdict must be != NULL */ size_t ZSTD_compressBegin_usingCDict_advanced( @@ -3771,8 +3796,8 @@ size_t ZSTD_compressBegin_usingCDict_advanced( ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) { if (cdict==NULL) return ERROR(dictionary_wrong); - { ZSTD_parameters params = - ZSTD_getParamsFromCCtxParams(cdict->refContext->appliedParams); + { + ZSTD_CCtx_params params = cdict->refContext->appliedParams; params.fParams = fParams; DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced"); return ZSTD_compressBegin_internal(cctx, @@ -3858,6 +3883,8 @@ static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, ZSTD_parameters params, unsigned long long pledgedSrcSize) { + ZSTD_CCtx_params cctxParams = ZSTD_makeCCtxParamsFromParams(params); + cctxParams.compressionLevel = zcs->requestedParams.compressionLevel; DEBUGLOG(4, "ZSTD_resetCStream_internal"); /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); @@ -3866,7 +3893,7 @@ static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, CHECK_F( ZSTD_compressBegin_internal(zcs, dict, dictSize, dictMode, cdict, - params, pledgedSrcSize, + cctxParams, pledgedSrcSize, ZSTDb_buffered) ); zcs->inToCompress = 0; @@ -3883,8 +3910,8 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) ZSTD_parameters params = ZSTD_getParamsFromCCtxParams(zcs->requestedParams); params.fParams.contentSizeFlag = (pledgedSrcSize > 0); DEBUGLOG(5, "ZSTD_resetCStream"); - if (zcs->compressionLevel != ZSTD_CLEVEL_CUSTOM) { - params.cParams = ZSTD_getCParams(zcs->compressionLevel, pledgedSrcSize, 0 /* dictSize */); + if (zcs->requestedParams.compressionLevel != ZSTD_CLEVEL_CUSTOM) { + params.cParams = ZSTD_getCParams(zcs->requestedParams.compressionLevel, pledgedSrcSize, 0 /* dictSize */); } return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->dictMode, zcs->cdict, params, pledgedSrcSize); } @@ -3915,7 +3942,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); } else { if (cdict) { - ZSTD_parameters const cdictParams = ZSTD_getParamsFromCDict(cdict); + ZSTD_CCtx_params const cdictParams = ZSTD_getCCtxParamsFromCDict(cdict); params.cParams = cdictParams.cParams; /* cParams are enforced from cdict */ } ZSTD_freeCDict(zcs->cdictLocal); @@ -3924,7 +3951,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, } zcs->requestedParams = ZSTD_makeCCtxParamsFromParams(params); - zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM; + zcs->requestedParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->dictMode, zcs->cdict, params, pledgedSrcSize); } @@ -3957,14 +3984,14 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, { CHECK_F( ZSTD_checkCParams(params.cParams) ); zcs->requestedParams = ZSTD_makeCCtxParamsFromParams(params); - zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM; + zcs->requestedParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, pledgedSrcSize); } size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) { ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); - zcs->compressionLevel = compressionLevel; + zcs->requestedParams.compressionLevel = compressionLevel; return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, 0); } @@ -4171,8 +4198,8 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, const void* const prefix = cctx->prefix; size_t const prefixSize = cctx->prefixSize; ZSTD_parameters params = ZSTD_getParamsFromCCtxParams(cctx->requestedParams); - if (cctx->compressionLevel != ZSTD_CLEVEL_CUSTOM) - params.cParams = ZSTD_getCParams(cctx->compressionLevel, + if (cctx->requestedParams.compressionLevel != ZSTD_CLEVEL_CUSTOM) + params.cParams = ZSTD_getCParams(cctx->requestedParams.compressionLevel, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); cctx->prefix = NULL; cctx->prefixSize = 0; /* single usage */ assert(prefix==NULL || cctx->cdict==NULL); /* only one can be set */ diff --git a/lib/zstd.h b/lib/zstd.h index e428319d4..e5ff0a38e 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -1013,6 +1013,8 @@ ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value); +ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, ZSTD_CCtx_params* params); + /*! ZSTD_CCtx_setPledgedSrcSize() : * Total input data size to be compressed as a single frame. * This value will be controlled at the end, and result in error if not respected. From b6cb2ed8cb6eaf57f7f8a1c967e6f8590a998205 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 18 Aug 2017 11:43:31 -0700 Subject: [PATCH 006/248] Move dictMode to cctxParams --- lib/common/zstd_internal.h | 2 + lib/compress/zstd_compress.c | 76 +++++++++++++++++++++--------------- lib/zstd.h | 2 +- 3 files changed, 47 insertions(+), 33 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 7c806b87c..b1cbd05a7 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -225,6 +225,8 @@ typedef struct ZSTD_CCtx_params_s { ZSTD_compressionParameters cParams; ZSTD_frameParameters fParams; int compressionLevel; + U32 forceWindow; + ZSTD_dictMode_e dictMode; } ZSTD_CCtx_params; diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 1ffeb5565..ada9d4f57 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -80,7 +80,7 @@ struct ZSTD_CCtx_s { U32 nextToUpdate3; /* index from which to continue dictionary update */ U32 hashLog3; /* dispatch table : larger == faster, more memory */ U32 loadedDictEnd; /* index of end of dictionary */ - U32 forceWindow; /* force back-references to respect limit of 1<forceWindow = value>0; cctx->loadedDictEnd = 0; return 0; + case ZSTD_p_forceWindow : + cctx->requestedParams.forceWindow = value>0; + cctx->loadedDictEnd = 0; + return 0; ZSTD_STATIC_ASSERT(ZSTD_dm_auto==0); ZSTD_STATIC_ASSERT(ZSTD_dm_rawContent==1); - case ZSTD_p_forceRawDict : cctx->dictMode = (ZSTD_dictMode_e)(value>0); return 0; + case ZSTD_p_forceRawDict : + cctx->requestedParams.dictMode = (ZSTD_dictMode_e)(value>0); + return 0; default: return ERROR(parameter_unsupported); } } @@ -407,7 +412,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v ZSTD_STATIC_ASSERT((U32)ZSTD_dm_fullDict > (U32)ZSTD_dm_rawContent); if (value > (unsigned)ZSTD_dm_fullDict) return ERROR(parameter_outOfBound); - cctx->dictMode = (ZSTD_dictMode_e)value; + cctx->requestedParams.dictMode = (ZSTD_dictMode_e)value; return 0; case ZSTD_p_refDictContent : @@ -419,7 +424,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize, * even when referencing into Dictionary content * default : 0 when using a CDict, 1 when using a Prefix */ - cctx->forceWindow = value>0; + cctx->requestedParams.forceWindow = value>0; cctx->loadedDictEnd = 0; return 0; @@ -532,7 +537,7 @@ size_t ZSTD_CCtxParam_setParameter( if (value > (unsigned)ZSTD_dm_fullDict) { return ERROR(parameter_outOfBound); } -// cctx->dictMode = (ZSTD_dictMode_e)value; + params->dictMode = (ZSTD_dictMode_e)value; return 0; case ZSTD_p_refDictContent : @@ -540,7 +545,7 @@ size_t ZSTD_CCtxParam_setParameter( return 0; case ZSTD_p_forceMaxWindow : -// cctx->forceWindow = value > 0; + params->forceWindow = value > 0; return 0; case ZSTD_p_nbThreads : @@ -587,7 +592,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, s ZSTD_getCParams(cctx->requestedParams.compressionLevel, 0, dictSize); cctx->cdictLocal = ZSTD_createCDict_advanced( dict, dictSize, - cctx->dictContentByRef, cctx->dictMode, + cctx->dictContentByRef, cctx->requestedParams.dictMode, cParams, cctx->customMem); cctx->cdict = cctx->cdictLocal; if (cctx->cdictLocal == NULL) @@ -3244,7 +3249,7 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t zc->dictBase = zc->base; zc->base += ip - zc->nextSrc; zc->nextToUpdate = zc->dictLimit; - zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base); + zc->loadedDictEnd = zc->appliedParams.forceWindow ? 0 : (U32)(iend - zc->base); zc->nextSrc = iend; if (srcSize <= HASH_READ_SIZE) return 0; @@ -3417,14 +3422,13 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx, * @return : 0, or an error code */ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, - ZSTD_dictMode_e dictMode, const ZSTD_CDict* cdict, ZSTD_CCtx_params params, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { DEBUGLOG(4, "ZSTD_compressBegin_internal"); DEBUGLOG(4, "dict ? %s", dict ? "dict" : (cdict ? "cdict" : "none")); - DEBUGLOG(4, "dictMode : %u", (U32)dictMode); + DEBUGLOG(4, "dictMode : %u", (U32)(params.dictMode)); /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ @@ -3437,7 +3441,7 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, ZSTDcrp_continue, zbuff) ); - return ZSTD_compress_insertDictionary(cctx, dict, dictSize, dictMode); + return ZSTD_compress_insertDictionary(cctx, dict, dictSize, params.dictMode); } @@ -3451,9 +3455,10 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, ZSTD_CCtx_params cctxParams = cctx->requestedParams; cctxParams.cParams = params.cParams; cctxParams.fParams = params.fParams; + cctxParams.dictMode = ZSTD_dm_auto; /* compression parameters verification and optimization */ CHECK_F(ZSTD_checkCParams(params.cParams)); - return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL, + return ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL, cctxParams, pledgedSrcSize, ZSTDb_not_buffered); } @@ -3544,8 +3549,9 @@ static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, ZSTD_CCtx_params cctxParams = cctx->requestedParams; cctxParams.cParams = params.cParams; cctxParams.fParams = params.fParams; + cctxParams.dictMode = ZSTD_dm_auto; - CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL, + CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL, cctxParams, srcSize, ZSTDb_not_buffered) ); return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); } @@ -3621,6 +3627,7 @@ size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict); } +#if 0 static ZSTD_parameters ZSTD_makeParams(ZSTD_compressionParameters cParams, ZSTD_frameParameters fParams) { ZSTD_parameters params; @@ -3628,6 +3635,7 @@ static ZSTD_parameters ZSTD_makeParams(ZSTD_compressionParameters cParams, ZSTD_ params.fParams = fParams; return params; } +#endif static size_t ZSTD_initCDict_internal( ZSTD_CDict* cdict, @@ -3650,13 +3658,12 @@ static size_t ZSTD_initCDict_internal( { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */ - ZSTD_parameters const params = ZSTD_makeParams(cParams, fParams); - ZSTD_CCtx_params cctxParams = - ZSTD_makeCCtxParamsFromParams(params); - cctxParams.compressionLevel = - cdict->refContext->requestedParams.compressionLevel; + ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams; + cctxParams.cParams = cParams; + cctxParams.fParams = fParams; + cctxParams.dictMode = dictMode; CHECK_F( ZSTD_compressBegin_internal(cdict->refContext, - cdict->dictContent, dictSize, dictMode, + cdict->dictContent, dictSize, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered) ); @@ -3723,7 +3730,7 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict) ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( void *workspace, size_t workspaceSize, const void* dict, - size_t dictSize, unsigned byReference, ZSTD_dictMode_e dictMode, + size_t dictSize, unsigned byReference, ZSTD_CCtx_params* params) { ZSTD_compressionParameters cParams = params->cParams; @@ -3749,7 +3756,7 @@ ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( if (ZSTD_isError( ZSTD_initCDict_internal(cdict, dict, dictSize, - 1 /* byReference */, dictMode, + 1 /* byReference */, params->dictMode, cParams) )) return NULL; @@ -3775,9 +3782,10 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, ZSTD_compressionParameters cParams) { ZSTD_CCtx_params params = ZSTD_makeCCtxParamsFromCParams(cParams); + params.dictMode = dictMode; return ZSTD_initStaticCDict_advanced_opaque( workspace, workspaceSize, dict, dictSize, - byReference, dictMode, ¶ms); + byReference, ¶ms); } @@ -3799,9 +3807,10 @@ size_t ZSTD_compressBegin_usingCDict_advanced( { ZSTD_CCtx_params params = cdict->refContext->appliedParams; params.fParams = fParams; + params.dictMode = ZSTD_dm_auto; DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced"); return ZSTD_compressBegin_internal(cctx, - NULL, 0, ZSTD_dm_auto, + NULL, 0, cdict, params, pledgedSrcSize, ZSTDb_not_buffered); @@ -3885,13 +3894,14 @@ static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, { ZSTD_CCtx_params cctxParams = ZSTD_makeCCtxParamsFromParams(params); cctxParams.compressionLevel = zcs->requestedParams.compressionLevel; + cctxParams.dictMode = dictMode; DEBUGLOG(4, "ZSTD_resetCStream_internal"); /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ CHECK_F( ZSTD_compressBegin_internal(zcs, - dict, dictSize, dictMode, + dict, dictSize, cdict, cctxParams, pledgedSrcSize, ZSTDb_buffered) ); @@ -3913,7 +3923,7 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) if (zcs->requestedParams.compressionLevel != ZSTD_CLEVEL_CUSTOM) { params.cParams = ZSTD_getCParams(zcs->requestedParams.compressionLevel, pledgedSrcSize, 0 /* dictSize */); } - return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->dictMode, zcs->cdict, params, pledgedSrcSize); + return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->requestedParams.dictMode, zcs->cdict, params, pledgedSrcSize); } /*! ZSTD_initCStream_internal() : @@ -3936,7 +3946,8 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, } ZSTD_freeCDict(zcs->cdictLocal); zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, - zcs->dictContentByRef, zcs->dictMode, + zcs->dictContentByRef, + zcs->requestedParams.dictMode, params.cParams, zcs->customMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); @@ -3949,10 +3960,11 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, zcs->cdictLocal = NULL; zcs->cdict = cdict; } - - zcs->requestedParams = ZSTD_makeCCtxParamsFromParams(params); + zcs->requestedParams.cParams = params.cParams; + zcs->requestedParams.fParams = params.fParams; zcs->requestedParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; - return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->dictMode, zcs->cdict, params, pledgedSrcSize); + + return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->requestedParams.dictMode, zcs->cdict, params, pledgedSrcSize); } /* ZSTD_initCStream_usingCDict_advanced() : @@ -4212,7 +4224,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, } else #endif { - CHECK_F( ZSTD_resetCStream_internal(cctx, prefix, prefixSize, cctx->dictMode, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); + CHECK_F( ZSTD_resetCStream_internal(cctx, prefix, prefixSize, cctx->requestedParams.dictMode, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); } } /* compression stage */ diff --git a/lib/zstd.h b/lib/zstd.h index e5ff0a38e..be3d7c4cc 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -608,7 +608,7 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict( ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( void* workspace, size_t workspaceSize, const void* dict, size_t dictSize, - unsigned byReference, ZSTD_dictMode_e dictMode, + unsigned byReference, ZSTD_CCtx_params* params); ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); From 2300c58a6f2fd98b9fbf602cfae4d868b38ab87a Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 18 Aug 2017 12:03:16 -0700 Subject: [PATCH 007/248] Move dictContentByRef to cctx params --- lib/common/zstd_internal.h | 5 +++++ lib/compress/zstd_compress.c | 33 ++++++++++++++++++++------------- lib/zstd.h | 5 +++-- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index b1cbd05a7..f7359646e 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -224,9 +224,14 @@ typedef struct seqDef_s { typedef struct ZSTD_CCtx_params_s { ZSTD_compressionParameters cParams; ZSTD_frameParameters fParams; + int compressionLevel; U32 forceWindow; + + /* Dictionary */ ZSTD_dictMode_e dictMode; + U32 dictContentByRef; + } ZSTD_CCtx_params; diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index ada9d4f57..7802df507 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -117,7 +117,7 @@ struct ZSTD_CCtx_s { /* Dictionary */ // ZSTD_dictMode_e dictMode; /* select restricting dictionary to "rawContent" or "fullDict" only */ - U32 dictContentByRef; +// U32 dictContentByRef; ZSTD_CDict* cdictLocal; const ZSTD_CDict* cdict; const void* prefix; @@ -418,7 +418,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v case ZSTD_p_refDictContent : if (cctx->cdict) return ERROR(stage_wrong); /* must be set before loading */ /* dictionary content will be referenced, instead of copied */ - cctx->dictContentByRef = value>0; + cctx->requestedParams.dictContentByRef = value>0; return 0; case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize, @@ -541,7 +541,7 @@ size_t ZSTD_CCtxParam_setParameter( return 0; case ZSTD_p_refDictContent : -// cctx->dictContentByRef = value > 0; + params->dictContentByRef = value > 0; return 0; case ZSTD_p_forceMaxWindow : @@ -549,12 +549,15 @@ size_t ZSTD_CCtxParam_setParameter( return 0; case ZSTD_p_nbThreads : + // TODO return 0; case ZSTD_p_jobSize : + // TODO return 0; case ZSTD_p_overlapSizeLog : + // TODO return 0; default: return ERROR(parameter_unsupported); @@ -592,7 +595,8 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, s ZSTD_getCParams(cctx->requestedParams.compressionLevel, 0, dictSize); cctx->cdictLocal = ZSTD_createCDict_advanced( dict, dictSize, - cctx->dictContentByRef, cctx->requestedParams.dictMode, + cctx->requestedParams.dictContentByRef, + cctx->requestedParams.dictMode, cParams, cctx->customMem); cctx->cdict = cctx->cdictLocal; if (cctx->cdictLocal == NULL) @@ -3594,14 +3598,14 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcS /* ===== Dictionary API ===== */ size_t ZSTD_estimateCDictSize_advanced_opaque( - size_t dictSize, ZSTD_CCtx_params* params, unsigned byReference) + size_t dictSize, ZSTD_CCtx_params* params) { if (params == NULL) { return 0; } DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict)); DEBUGLOG(5, "CCtx estimate : %u", (U32)ZSTD_estimateCCtxSize_advanced_opaque(params)); return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced_opaque(params) - + (byReference ? 0 : dictSize); + + (params->dictContentByRef ? 0 : dictSize); } @@ -3610,7 +3614,8 @@ size_t ZSTD_estimateCDictSize_advanced_opaque( size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference) { ZSTD_CCtx_params params = ZSTD_makeCCtxParamsFromCParams(cParams); - return ZSTD_estimateCDictSize_advanced_opaque(dictSize, ¶ms, byReference); + params.dictContentByRef = byReference; + return ZSTD_estimateCDictSize_advanced_opaque(dictSize, ¶ms); } size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) @@ -3662,6 +3667,8 @@ static size_t ZSTD_initCDict_internal( cctxParams.cParams = cParams; cctxParams.fParams = fParams; cctxParams.dictMode = dictMode; + cctxParams.dictContentByRef = byReference; + CHECK_F( ZSTD_compressBegin_internal(cdict->refContext, cdict->dictContent, dictSize, NULL, @@ -3730,12 +3737,12 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict) ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( void *workspace, size_t workspaceSize, const void* dict, - size_t dictSize, unsigned byReference, + size_t dictSize, ZSTD_CCtx_params* params) { ZSTD_compressionParameters cParams = params->cParams; size_t const cctxSize = ZSTD_estimateCCtxSize_advanced(cParams); - size_t const neededSize = sizeof(ZSTD_CDict) + (byReference ? 0 : dictSize) + size_t const neededSize = sizeof(ZSTD_CDict) + (params->dictContentByRef ? 0 : dictSize) + cctxSize; ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; void* ptr; @@ -3745,7 +3752,7 @@ ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize)); if (workspaceSize < neededSize) return NULL; - if (!byReference) { + if (!params->dictContentByRef) { memcpy(cdict+1, dict, dictSize); dict = cdict+1; ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize; @@ -3783,12 +3790,12 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, { ZSTD_CCtx_params params = ZSTD_makeCCtxParamsFromCParams(cParams); params.dictMode = dictMode; + params.dictContentByRef = byReference; return ZSTD_initStaticCDict_advanced_opaque( workspace, workspaceSize, dict, dictSize, - byReference, ¶ms); + ¶ms); } - ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) { return ZSTD_getParamsFromCCtx(cdict->refContext); } @@ -3946,7 +3953,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, } ZSTD_freeCDict(zcs->cdictLocal); zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, - zcs->dictContentByRef, + zcs->requestedParams.dictContentByRef, zcs->requestedParams.dictMode, params.cParams, zcs->customMem); zcs->cdict = zcs->cdictLocal; diff --git a/lib/zstd.h b/lib/zstd.h index be3d7c4cc..56316160a 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -528,7 +528,9 @@ ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t sr * Note : dictionary created "byReference" are smaller */ ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference); -ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced_opaque(size_t dictSize, ZSTD_CCtx_params* params, unsigned byReference); + +// By reference +ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced_opaque(size_t dictSize, ZSTD_CCtx_params* params); ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference); @@ -608,7 +610,6 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict( ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( void* workspace, size_t workspaceSize, const void* dict, size_t dictSize, - unsigned byReference, ZSTD_CCtx_params* params); ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); From 81d89d82a69681567934d7f48c2dfb8a9ca409d8 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 18 Aug 2017 12:08:57 -0700 Subject: [PATCH 008/248] Move nbThreads to cctx params --- lib/common/zstd_internal.h | 2 ++ lib/compress/zstd_compress.c | 27 ++++++++++++++++----------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index f7359646e..7ea2ecc47 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -232,6 +232,8 @@ typedef struct ZSTD_CCtx_params_s { ZSTD_dictMode_e dictMode; U32 dictContentByRef; + /* Multithreading */ + U32 nbThreads; } ZSTD_CCtx_params; diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 7802df507..e47ae9a1e 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -124,7 +124,7 @@ struct ZSTD_CCtx_s { size_t prefixSize; /* Multi-threading */ - U32 nbThreads; +// U32 nbThreads; ZSTDMT_CCtx* mtctx; }; @@ -434,25 +434,25 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v #ifndef ZSTD_MULTITHREAD if (value > 1) return ERROR(parameter_unsupported); #endif - if ((value>1) && (cctx->nbThreads != value)) { + if ((value>1) && (cctx->requestedParams.nbThreads != value)) { if (cctx->staticSize) /* MT not compatible with static alloc */ return ERROR(parameter_unsupported); ZSTDMT_freeCCtx(cctx->mtctx); - cctx->nbThreads = 1; + cctx->requestedParams.nbThreads = 1; cctx->mtctx = ZSTDMT_createCCtx_advanced(value, cctx->customMem); if (cctx->mtctx == NULL) return ERROR(memory_allocation); } - cctx->nbThreads = value; + cctx->requestedParams.nbThreads = value; return 0; case ZSTD_p_jobSize: - if (cctx->nbThreads <= 1) return ERROR(parameter_unsupported); + if (cctx->requestedParams.nbThreads <= 1) return ERROR(parameter_unsupported); assert(cctx->mtctx != NULL); return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_sectionSize, value); case ZSTD_p_overlapSizeLog: - DEBUGLOG(5, " setting overlap with nbThreads == %u", cctx->nbThreads); - if (cctx->nbThreads <= 1) return ERROR(parameter_unsupported); + DEBUGLOG(5, " setting overlap with nbThreads == %u", cctx->requestedParams.nbThreads); + if (cctx->requestedParams.nbThreads <= 1) return ERROR(parameter_unsupported); assert(cctx->mtctx != NULL); return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_overlapSectionLog, value); @@ -549,7 +549,12 @@ size_t ZSTD_CCtxParam_setParameter( return 0; case ZSTD_p_nbThreads : - // TODO + if (value == 0) { return 0; } +#ifndef ZSTD_MULTITHREAD + if (value > 1) return ERROR(parameter_unsupported); +#endif + // Do checks when applying parameters to cctx. + params->nbThreads = value; return 0; case ZSTD_p_jobSize : @@ -4224,8 +4229,8 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, assert(prefix==NULL || cctx->cdict==NULL); /* only one can be set */ #ifdef ZSTD_MULTITHREAD - if (cctx->nbThreads > 1) { - DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", cctx->nbThreads); + if (cctx->requestedParams.nbThreads > 1) { + DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", cctx->requestedParams.nbThreads); CHECK_F( ZSTDMT_initCStream_internal(cctx->mtctx, prefix, prefixSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); cctx->streamStage = zcss_load; } else @@ -4236,7 +4241,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, /* compression stage */ #ifdef ZSTD_MULTITHREAD - if (cctx->nbThreads > 1) { + if (cctx->requestedParams.nbThreads > 1) { size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); DEBUGLOG(5, "ZSTDMT_compressStream_generic : %u", (U32)flushMin); if ( ZSTD_isError(flushMin) From 399ae013d4028bb197b14b183cb91b53742884f6 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 18 Aug 2017 13:01:55 -0700 Subject: [PATCH 009/248] Add function to apply cctx params --- lib/common/zstd_internal.h | 34 ++++++++++++++++++---------------- lib/compress/zstd_compress.c | 29 +++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 7ea2ecc47..fa9f0c49c 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -221,22 +221,6 @@ typedef struct seqDef_s { U16 matchLength; } seqDef; -typedef struct ZSTD_CCtx_params_s { - ZSTD_compressionParameters cParams; - ZSTD_frameParameters fParams; - - int compressionLevel; - U32 forceWindow; - - /* Dictionary */ - ZSTD_dictMode_e dictMode; - U32 dictContentByRef; - - /* Multithreading */ - U32 nbThreads; - -} ZSTD_CCtx_params; - typedef struct { seqDef* sequencesStart; seqDef* sequences; @@ -251,6 +235,24 @@ typedef struct { U32 repToConfirm[ZSTD_REP_NUM]; } seqStore_t; +struct ZSTD_CCtx_params_s { + ZSTD_compressionParameters cParams; + ZSTD_frameParameters fParams; + + int compressionLevel; + + U32 forceWindow; /* force back-references to respect limit of 1<nbThreads <= 1) { return ERROR(parameter_unsupported); } + params->jobSize = value; return 0; case ZSTD_p_overlapSizeLog : - // TODO + params->overlapSizeLog = value; return 0; default: return ERROR(parameter_unsupported); } } +// This function should probably be updated whenever ZSTD_CCtx_params is updated. ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, ZSTD_CCtx_params* params) { - (void)cctx; - (void)params; + if (cctx->cdict) { return ERROR(stage_wrong); } + + /* Assume the compression and frame parameters are validated */ + cctx->requestedParams.cParams = params->cParams; + cctx->requestedParams.fParams = params->fParams; + cctx->requestedParams.compressionLevel = params->compressionLevel; + + /* Assume dictionary parameters are validated */ + cctx->requestedParams.dictMode = params->dictMode; + cctx->requestedParams.dictContentByRef = params->dictContentByRef; + + /* Set force window explicitly since it sets cctx->loadedDictEnd */ + CHECK_F( ZSTD_CCtx_setParameter( + cctx, ZSTD_p_forceMaxWindow, params->forceWindow) ); + + /* Set multithreading parameters explicitly */ + CHECK_F( ZSTD_CCtx_setParameter(cctx, ZSTD_p_nbThreads, params->nbThreads) ); + CHECK_F( ZSTD_CCtx_setParameter(cctx, ZSTD_p_jobSize, params->jobSize) ); + CHECK_F( ZSTD_CCtx_setParameter( + cctx, ZSTD_p_overlapSizeLog, params->overlapSizeLog) ); return 0; } From 63b8c985317b38e69b69fa69f4727e8d55ce2cb4 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 18 Aug 2017 16:17:24 -0700 Subject: [PATCH 010/248] Pass cctx parameters to MTCtx --- lib/compress/zstd_compress.c | 108 ++++++++++++++++++++++++--------- lib/compress/zstdmt_compress.c | 107 +++++++++++++++++++++++--------- lib/compress/zstdmt_compress.h | 9 +++ 3 files changed, 165 insertions(+), 59 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 426636cfc..b63519d9a 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -213,7 +213,7 @@ static ZSTD_parameters ZSTD_getParamsFromCCtxParams(const ZSTD_CCtx_params cctxP } // TODO: get rid of this function too -static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromParams(ZSTD_parameters params) { +ZSTD_CCtx_params ZSTD_makeCCtxParamsFromParams(ZSTD_parameters params) { ZSTD_CCtx_params cctxParams; memset(&cctxParams, 0, sizeof(ZSTD_CCtx_params)); cctxParams.cParams = params.cParams; @@ -3474,6 +3474,17 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, return ZSTD_compress_insertDictionary(cctx, dict, dictSize, params.dictMode); } +size_t ZSTD_compressBegin_advanced_opaque(ZSTD_CCtx* cctx, + const void* dict, size_t dictSize, + ZSTD_CCtx_params params, + unsigned long long pledgedSrcSize) +{ + /* compression parameters verification and optimization */ + CHECK_F( ZSTD_checkCParams(params.cParams) ); + return ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL, + params, pledgedSrcSize, + ZSTDb_not_buffered); +} /*! ZSTD_compressBegin_advanced() : * @return : 0, or an error code */ @@ -3481,15 +3492,13 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params cctxParams = cctx->requestedParams; cctxParams.cParams = params.cParams; cctxParams.fParams = params.fParams; cctxParams.dictMode = ZSTD_dm_auto; - /* compression parameters verification and optimization */ - CHECK_F(ZSTD_checkCParams(params.cParams)); - return ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL, - cctxParams, pledgedSrcSize, ZSTDb_not_buffered); + + return ZSTD_compressBegin_advanced_opaque(cctx, dict, dictSize, cctxParams, + pledgedSrcSize); } @@ -3580,10 +3589,11 @@ static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, cctxParams.cParams = params.cParams; cctxParams.fParams = params.fParams; cctxParams.dictMode = ZSTD_dm_auto; - - CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL, - cctxParams, srcSize, ZSTDb_not_buffered) ); - return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); + return ZSTD_compress_advanced_opaque(cctx, + dst, dstCapacity, + src, srcSize, + dict, dictSize, + cctxParams); } size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, @@ -3596,6 +3606,18 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params); } +/* Internal */ +size_t ZSTD_compress_advanced_opaque(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + ZSTD_CCtx_params params) +{ + CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL, + params, srcSize, ZSTDb_not_buffered) ); + return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); +} + size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize, int compressionLevel) { @@ -3920,14 +3942,13 @@ size_t ZSTD_CStreamOutSize(void) return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; } -static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, - const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, - const ZSTD_CDict* cdict, - ZSTD_parameters params, unsigned long long pledgedSrcSize) +static size_t ZSTD_resetCStream_internal_opaque( + ZSTD_CStream* zcs, + const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, + const ZSTD_CDict* cdict, + ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params cctxParams = ZSTD_makeCCtxParamsFromParams(params); - cctxParams.compressionLevel = zcs->requestedParams.compressionLevel; - cctxParams.dictMode = dictMode; + params.dictMode = dictMode; DEBUGLOG(4, "ZSTD_resetCStream_internal"); /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); @@ -3936,7 +3957,7 @@ static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, CHECK_F( ZSTD_compressBegin_internal(zcs, dict, dictSize, cdict, - cctxParams, pledgedSrcSize, + params, pledgedSrcSize, ZSTDb_buffered) ); zcs->inToCompress = 0; @@ -3948,6 +3969,19 @@ static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, return 0; /* ready to go */ } +static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, + const ZSTD_CDict* cdict, + ZSTD_parameters params, unsigned long long pledgedSrcSize) +{ + ZSTD_CCtx_params cctxParams = zcs->requestedParams; + cctxParams.cParams = params.cParams; + cctxParams.fParams = params.fParams; + cctxParams.dictMode = dictMode; + return ZSTD_resetCStream_internal_opaque(zcs, dict, dictSize, dictMode, + cdict, cctxParams, pledgedSrcSize); +} + size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) { ZSTD_parameters params = ZSTD_getParamsFromCCtxParams(zcs->requestedParams); @@ -3959,13 +3993,11 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->requestedParams.dictMode, zcs->cdict, params, pledgedSrcSize); } -/*! ZSTD_initCStream_internal() : - * Note : not static, but hidden (not exposed). Used by zstdmt_compress.c - * Assumption 1 : params are valid - * Assumption 2 : either dict, or cdict, is defined, not both */ -size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, - const void* dict, size_t dictSize, const ZSTD_CDict* cdict, - ZSTD_parameters params, unsigned long long pledgedSrcSize) +size_t ZSTD_initCStream_internal_opaque(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + const ZSTD_CDict* cdict, + ZSTD_CCtx_params params, + unsigned long long pledgedSrcSize) { DEBUGLOG(5, "ZSTD_initCStream_internal"); assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); @@ -3993,11 +4025,28 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, zcs->cdictLocal = NULL; zcs->cdict = cdict; } - zcs->requestedParams.cParams = params.cParams; - zcs->requestedParams.fParams = params.fParams; - zcs->requestedParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; + zcs->requestedParams = params; - return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->requestedParams.dictMode, zcs->cdict, params, pledgedSrcSize); + return ZSTD_resetCStream_internal_opaque( + zcs, NULL, 0, zcs->requestedParams.dictMode, zcs->cdict, + params, pledgedSrcSize); +} + + +/*! ZSTD_initCStream_internal() : + * Note : not static, but hidden (not exposed). Used by zstdmt_compress.c + * Assumption 1 : params are valid + * Assumption 2 : either dict, or cdict, is defined, not both */ +size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, const ZSTD_CDict* cdict, + ZSTD_parameters params, unsigned long long pledgedSrcSize) +{ + ZSTD_CCtx_params cctxParams = zcs->requestedParams; + cctxParams.cParams = params.cParams; + cctxParams.fParams = params.fParams; + cctxParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; + return ZSTD_initCStream_internal_opaque(zcs, dict, dictSize, cdict, + cctxParams, pledgedSrcSize); } /* ZSTD_initCStream_usingCDict_advanced() : @@ -4227,7 +4276,6 @@ size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, const void* dict, size_t dictSize, const ZSTD_CDict* cdict, ZSTD_parameters params, unsigned long long pledgedSrcSize); - size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input, diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 234ced9de..2eb714e60 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -186,6 +186,14 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf) ZSTD_free(buf.start, bufPool->cMem); } +static void ZSTDMT_zeroCCtxParams(ZSTD_CCtx_params* params) +{ + params->forceWindow = 0; + params->dictMode = (ZSTD_dictMode_e)(0); + params->nbThreads = 0; + params->jobSize = 0; + params->overlapSizeLog = 0; +} /* ===== CCtx Pool ===== */ /* a single CCtx Pool can be invoked from multiple threads in parallel */ @@ -292,7 +300,7 @@ typedef struct { unsigned jobScanned; pthread_mutex_t* jobCompleted_mutex; pthread_cond_t* jobCompleted_cond; - ZSTD_parameters params; + ZSTD_CCtx_params params; const ZSTD_CDict* cdict; ZSTDMT_CCtxPool* cctxPool; ZSTDMT_bufferPool* bufPool; @@ -330,7 +338,7 @@ void ZSTDMT_compressChunk(void* jobDescription) } else { /* srcStart points at reloaded section */ if (!job->firstChunk) job->params.fParams.contentSizeFlag = 0; /* ensure no srcSize control */ { size_t const dictModeError = ZSTD_setCCtxParameter(cctx, ZSTD_p_forceRawDict, 1); /* Force loading dictionary in "content-only" mode (no header analysis) */ - size_t const initError = ZSTD_compressBegin_advanced(cctx, job->srcStart, job->dictSize, job->params, job->fullFrameSize); + size_t const initError = ZSTD_compressBegin_advanced_opaque(cctx, job->srcStart, job->dictSize, job->params, job->fullFrameSize); if (ZSTD_isError(initError) || ZSTD_isError(dictModeError)) { job->cSize = initError; goto _endJob; } ZSTD_setCCtxParameter(cctx, ZSTD_p_forceWindow, 1); } } @@ -382,7 +390,7 @@ struct ZSTDMT_CCtx_s { size_t dictSize; size_t targetDictSize; inBuff_t inBuff; - ZSTD_parameters params; + ZSTD_CCtx_params params; XXH64_state_t xxhState; unsigned nbThreads; unsigned jobIDMask; @@ -528,17 +536,17 @@ static unsigned computeNbChunks(size_t srcSize, unsigned windowLog, unsigned nbT return (multiplier>1) ? nbChunksLarge : nbChunksSmall; } - -size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const ZSTD_CDict* cdict, - ZSTD_parameters const params, - unsigned overlapLog) +static size_t ZSTDMT_compress_advanced_opaque( + ZSTDMT_CCtx* mtctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict, + ZSTD_CCtx_params const cctxParams, + unsigned overlapLog) { unsigned const overlapRLog = (overlapLog>9) ? 0 : 9-overlapLog; - size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (params.cParams.windowLog - overlapRLog); - unsigned nbChunks = computeNbChunks(srcSize, params.cParams.windowLog, mtctx->nbThreads); + size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (cctxParams.cParams.windowLog - overlapRLog); + unsigned nbChunks = computeNbChunks(srcSize, cctxParams.cParams.windowLog, mtctx->nbThreads); size_t const proposedChunkSize = (srcSize + (nbChunks-1)) / nbChunks; size_t const avgChunkSize = ((proposedChunkSize & 0x1FFFF) < 0x7FFF) ? proposedChunkSize + 0xFFFF : proposedChunkSize; /* avoid too small last block */ const char* const srcStart = (const char*)src; @@ -546,12 +554,15 @@ size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbChunks : (unsigned)(dstCapacity / ZSTD_compressBound(avgChunkSize)); /* presumes avgChunkSize >= 256 KB, which should be the case */ size_t frameStartPos = 0, dstBufferPos = 0; XXH64_state_t xxh64; + ZSTD_CCtx_params requestedParams = cctxParams; + ZSTDMT_zeroCCtxParams(&requestedParams); DEBUGLOG(4, "nbChunks : %2u (chunkSize : %u bytes) ", nbChunks, (U32)avgChunkSize); if (nbChunks==1) { /* fallback to single-thread mode */ ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0]; - if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, params.fParams); - return ZSTD_compress_advanced(cctx, dst, dstCapacity, src, srcSize, NULL, 0, params); + + if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, cctxParams.fParams); + return ZSTD_compress_advanced_opaque(cctx, dst, dstCapacity, src, srcSize, NULL, 0, requestedParams); } assert(avgChunkSize >= 256 KB); /* condition for ZSTD_compressBound(A) + ZSTD_compressBound(B) <= ZSTD_compressBound(A+B), which is required for compressWithinDst */ ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(avgChunkSize) ); @@ -580,7 +591,7 @@ size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, mtctx->jobs[u].srcSize = chunkSize; mtctx->jobs[u].cdict = mtctx->nextJobID==0 ? cdict : NULL; mtctx->jobs[u].fullFrameSize = srcSize; - mtctx->jobs[u].params = params; + mtctx->jobs[u].params = requestedParams; /* do not calculate checksum within sections, but write it in header for first section */ if (u!=0) mtctx->jobs[u].params.fParams.checksumFlag = 0; mtctx->jobs[u].dstBuff = dstBuffer; @@ -592,7 +603,7 @@ size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, mtctx->jobs[u].jobCompleted_mutex = &mtctx->jobCompleted_mutex; mtctx->jobs[u].jobCompleted_cond = &mtctx->jobCompleted_cond; - if (params.fParams.checksumFlag) { + if (cctxParams.fParams.checksumFlag) { XXH64_update(&xxh64, srcStart + frameStartPos, chunkSize); } @@ -636,7 +647,7 @@ size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, } /* for (chunkID=0; chunkID dstCapacity) { error = ERROR(dstSize_tooSmall); @@ -649,6 +660,23 @@ size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, if (!error) DEBUGLOG(4, "compressed size : %u ", (U32)dstPos); return error ? error : dstPos; } + +} + +size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict, + ZSTD_parameters const params, + unsigned overlapLog) +{ + ZSTD_CCtx_params cctxParams = mtctx->params; + cctxParams.cParams = params.cParams; + cctxParams.fParams = params.fParams; + return ZSTDMT_compress_advanced_opaque(mtctx, + dst, dstCapacity, + src, srcSize, + cdict, cctxParams, overlapLog); } @@ -683,23 +711,28 @@ static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs) } } - -/** ZSTDMT_initCStream_internal() : - * internal usage only */ -size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, - const void* dict, size_t dictSize, const ZSTD_CDict* cdict, - ZSTD_parameters params, unsigned long long pledgedSrcSize) +size_t ZSTDMT_initCStream_internal_opaque( + ZSTDMT_CCtx* zcs, const void* dict, size_t dictSize, + const ZSTD_CDict* cdict, ZSTD_CCtx_params cctxParams, + unsigned long long pledgedSrcSize) { + ZSTD_parameters params; + params.cParams = cctxParams.cParams; + params.fParams = cctxParams.fParams; + DEBUGLOG(4, "ZSTDMT_initCStream_internal"); /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ + /* TODO: Set stuff to 0 to preserve old semantics. */ + ZSTDMT_zeroCCtxParams(&cctxParams); + if (zcs->nbThreads==1) { DEBUGLOG(4, "single thread mode"); - return ZSTD_initCStream_internal(zcs->cctxPool->cctx[0], - dict, dictSize, cdict, - params, pledgedSrcSize); + return ZSTD_initCStream_internal_opaque(zcs->cctxPool->cctx[0], + dict, dictSize, cdict, + cctxParams, pledgedSrcSize); } if (zcs->allJobsCompleted == 0) { /* previous compression not correctly finished */ @@ -708,7 +741,7 @@ size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, zcs->allJobsCompleted = 1; } - zcs->params = params; + zcs->params = cctxParams; zcs->frameContentSize = pledgedSrcSize; if (dict) { DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal); @@ -742,6 +775,21 @@ size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, zcs->allJobsCompleted = 0; if (params.fParams.checksumFlag) XXH64_reset(&zcs->xxhState, 0); return 0; + +} + + +/** ZSTDMT_initCStream_internal() : + * internal usage only */ +size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, + const void* dict, size_t dictSize, const ZSTD_CDict* cdict, + ZSTD_parameters params, unsigned long long pledgedSrcSize) +{ + ZSTD_CCtx_params cctxParams = zcs->params; + cctxParams.cParams = params.cParams; + cctxParams.fParams = params.fParams; + return ZSTDMT_initCStream_internal_opaque(zcs, dict, dictSize, cdict, + cctxParams, pledgedSrcSize); } size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx, @@ -772,7 +820,8 @@ size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* zcs, unsigned long long pledgedSrcSize) { if (zcs->nbThreads==1) return ZSTD_resetCStream(zcs->cctxPool->cctx[0], pledgedSrcSize); - return ZSTDMT_initCStream_internal(zcs, NULL, 0, 0, zcs->params, pledgedSrcSize); + return ZSTDMT_initCStream_internal_opaque(zcs, NULL, 0, 0, zcs->params, + pledgedSrcSize); } size_t ZSTDMT_initCStream(ZSTDMT_CCtx* zcs, int compressionLevel) { @@ -930,7 +979,7 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, && (mtctx->inBuff.filled==0) /* nothing buffered */ && (endOp==ZSTD_e_end) /* end order */ && (output->size - output->pos >= ZSTD_compressBound(input->size - input->pos)) ) { /* enough room */ - size_t const cSize = ZSTDMT_compress_advanced(mtctx, + size_t const cSize = ZSTDMT_compress_advanced_opaque(mtctx, (char*)output->dst + output->pos, output->size - output->pos, (const char*)input->src + input->pos, input->size - input->pos, mtctx->cdict, mtctx->params, mtctx->overlapLog); diff --git a/lib/compress/zstdmt_compress.h b/lib/compress/zstdmt_compress.h index 843a240aa..0b478b735 100644 --- a/lib/compress/zstdmt_compress.h +++ b/lib/compress/zstdmt_compress.h @@ -69,6 +69,15 @@ ZSTDLIB_API size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, const ZSTD_CDict* cdict, ZSTD_parameters const params, unsigned overlapLog); +#if 0 +ZSTDLIB_API size_t ZSTDMT_compress_advanced_opaque( + ZSTDMT_CCtx* mtctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict, + ZSTD_CCtx_params* const params, + unsigned overlapLog); +#endif ZSTDLIB_API size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx, const void* dict, size_t dictSize, /* dict can be released after init, a local copy is preserved within zcs */ From d77551929654d35bf46ebad1f0ebd6f0e31b6ccf Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 18 Aug 2017 17:37:58 -0700 Subject: [PATCH 011/248] Add cctxParam versions of internal functions --- lib/common/zstd_internal.h | 23 ++++- lib/compress/zstd_compress.c | 169 +++++++++++++++++++-------------- lib/compress/zstdmt_compress.c | 8 +- 3 files changed, 122 insertions(+), 78 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index fa9f0c49c..0da950787 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -351,10 +351,11 @@ void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx); * expects params to be valid. * must receive dict, or cdict, or none, but not both. * @return : 0, or an error code */ -size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, - const void* dict, size_t dictSize, - const ZSTD_CDict* cdict, - ZSTD_parameters params, unsigned long long pledgedSrcSize); +size_t ZSTD_initCStream_internal_opaque(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + const ZSTD_CDict* cdict, + ZSTD_CCtx_params params, + unsigned long long pledgedSrcSize); /*! ZSTD_compressStream_generic() : * Private use only. To be called from zstdmt_compress.c in single-thread mode. */ @@ -365,8 +366,20 @@ size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, /*! ZSTD_getParamsFromCDict() : * as the name implies */ -ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict); +ZSTD_CCtx_params ZSTD_getCCtxParamsFromCDict(const ZSTD_CDict* cdict); +/* INTERNAL */ +size_t ZSTD_compressBegin_advanced_opaque(ZSTD_CCtx* cctx, + const void* dict, size_t dictSize, + ZSTD_CCtx_params params, + unsigned long long pledgedSrcSize); + +/* INTERNAL */ +size_t ZSTD_compress_advanced_opaque(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + ZSTD_CCtx_params params); typedef struct { blockType_e blockType; diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index b63519d9a..434f40562 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -203,6 +203,7 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) /* private API call, for dictBuilder only */ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } +#if 0 // TODO: get rid of this function static ZSTD_parameters ZSTD_getParamsFromCCtxParams(const ZSTD_CCtx_params cctxParams) { @@ -211,15 +212,18 @@ static ZSTD_parameters ZSTD_getParamsFromCCtxParams(const ZSTD_CCtx_params cctxP params.fParams = cctxParams.fParams; return params; } +#endif +#if 0 // TODO: get rid of this function too -ZSTD_CCtx_params ZSTD_makeCCtxParamsFromParams(ZSTD_parameters params) { +static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromParams(ZSTD_parameters params) { ZSTD_CCtx_params cctxParams; memset(&cctxParams, 0, sizeof(ZSTD_CCtx_params)); cctxParams.cParams = params.cParams; cctxParams.fParams = params.fParams; return cctxParams; } +#endif // TODO: get rid of this function too static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( @@ -230,11 +234,12 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( cctxParams.cParams = cParams; return cctxParams; } - +#if 0 // TODO: get rid of this function static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { return ZSTD_getParamsFromCCtxParams(cctx->appliedParams); } +#endif /* older variant; will be deprecated */ size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value) @@ -292,7 +297,7 @@ ZSTD_CCtx_params* ZSTD_createAndInitCCtxParams( if (params == NULL) { return NULL; } ZSTD_initCCtxParams(params, ZSTD_getCParams( compressionLevel, estimatedSrcSize, dictSize)); - params->compressionLevel = compressionLevel; + params->compressionLevel = ZSTD_CLEVEL_CUSTOM; return params; } @@ -786,10 +791,9 @@ size_t ZSTD_estimateCStreamSize_advanced_opaque(ZSTD_CCtx_params* params) { if (params == NULL) { return 0; } { - ZSTD_compressionParameters cParams = params->cParams; - size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced(cParams); - size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); - size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize; + size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced_opaque(params); + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog); + size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize; size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; size_t const streamingSize = inBuffSize + outBuffSize; @@ -808,9 +812,8 @@ size_t ZSTD_estimateCStreamSize(int compressionLevel) { return ZSTD_estimateCStreamSize_advanced(cParams); } - -static U32 ZSTD_equivalentParams(ZSTD_compressionParameters cParams1, - ZSTD_compressionParameters cParams2) +static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1, + ZSTD_compressionParameters cParams2) { U32 bslog1 = MIN(cParams1.windowLog, ZSTD_BLOCKSIZELOG_MAX); U32 bslog2 = MIN(cParams2.windowLog, ZSTD_BLOCKSIZELOG_MAX); @@ -821,6 +824,13 @@ static U32 ZSTD_equivalentParams(ZSTD_compressionParameters cParams1, & ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */ } +/** Equivalence for resetCCtx purposes */ +static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1, + ZSTD_CCtx_params params2) +{ + return ZSTD_equivalentCParams(params1.cParams, params2.cParams); +} + /*! ZSTD_continueCCtx() : * reuse CCtx without reset (note : requires no dictionary) */ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize) @@ -859,8 +869,8 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); if (crp == ZSTDcrp_continue) { - if (ZSTD_equivalentParams(params.cParams, zc->appliedParams.cParams)) { - DEBUGLOG(5, "ZSTD_equivalentParams()==1"); + if (ZSTD_equivalentParams(params, zc->appliedParams)) { + DEBUGLOG(5, "ZSTD_equivalentCParams()==1"); zc->entropy->hufCTable_repeatMode = HUF_repeat_none; zc->entropy->offcode_repeatMode = FSE_repeat_none; zc->entropy->matchlength_repeatMode = FSE_repeat_none; @@ -3255,6 +3265,7 @@ size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) ZSTD_compressionParameters cParams = (cLevel == ZSTD_CLEVEL_CUSTOM) ? cctx->appliedParams.cParams : ZSTD_getCParams(cLevel, 0, 0); + DEBUGLOG(2, "ZSTD_getBlockSize: cLevel %u\n", cLevel); return MIN (ZSTD_BLOCKSIZE_MAX, 1 << cParams.windowLog); } @@ -3490,7 +3501,8 @@ size_t ZSTD_compressBegin_advanced_opaque(ZSTD_CCtx* cctx, * @return : 0, or an error code */ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, - ZSTD_parameters params, unsigned long long pledgedSrcSize) + ZSTD_parameters params, + unsigned long long pledgedSrcSize) { ZSTD_CCtx_params cctxParams = cctx->requestedParams; cctxParams.cParams = params.cParams; @@ -3618,8 +3630,11 @@ size_t ZSTD_compress_advanced_opaque(ZSTD_CCtx* cctx, return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); } -size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, - const void* dict, size_t dictSize, int compressionLevel) +size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, + size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict, size_t dictSize, + int compressionLevel) { ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0); params.fParams.contentSizeFlag = 1; @@ -3690,14 +3705,12 @@ static ZSTD_parameters ZSTD_makeParams(ZSTD_compressionParameters cParams, ZSTD_ } #endif -static size_t ZSTD_initCDict_internal( - ZSTD_CDict* cdict, - const void* dictBuffer, size_t dictSize, - unsigned byReference, ZSTD_dictMode_e dictMode, - ZSTD_compressionParameters cParams) +static size_t ZSTD_initCDict_internal_opaque(ZSTD_CDict* cdict, + const void* dictBuffer, size_t dictSize, + ZSTD_CCtx_params params) { - DEBUGLOG(5, "ZSTD_initCDict_internal, mode %u", (U32)dictMode); - if ((byReference) || (!dictBuffer) || (!dictSize)) { + DEBUGLOG(5, "ZSTD_initCDict_internal_opaque, mode %u", (U32)params.dictMode); + if ((params.dictContentByRef) || (!dictBuffer) || (!dictSize)) { cdict->dictBuffer = NULL; cdict->dictContent = dictBuffer; } else { @@ -3709,21 +3722,30 @@ static size_t ZSTD_initCDict_internal( } cdict->dictContentSize = dictSize; - { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, + /* Frame parameters should be zero? */ + CHECK_F( ZSTD_compressBegin_internal(cdict->refContext, + cdict->dictContent, dictSize, + NULL, + params, ZSTD_CONTENTSIZE_UNKNOWN, + ZSTDb_not_buffered) ); + return 0; +} + +static size_t ZSTD_initCDict_internal( + ZSTD_CDict* cdict, + const void* dictBuffer, size_t dictSize, + unsigned byReference, ZSTD_dictMode_e dictMode, + ZSTD_compressionParameters cParams) +{ + ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams; + ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */ - ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams; - cctxParams.cParams = cParams; - cctxParams.fParams = fParams; - cctxParams.dictMode = dictMode; - cctxParams.dictContentByRef = byReference; - - CHECK_F( ZSTD_compressBegin_internal(cdict->refContext, - cdict->dictContent, dictSize, - NULL, - cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, - ZSTDb_not_buffered) ); - } - + cctxParams.cParams = cParams; + cctxParams.fParams = fParams; + cctxParams.dictMode = dictMode; + cctxParams.dictContentByRef = byReference; + CHECK_F (ZSTD_initCDict_internal_opaque( + cdict, dictBuffer, dictSize, cctxParams) ); return 0; } @@ -3788,8 +3810,7 @@ ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( size_t dictSize, ZSTD_CCtx_params* params) { - ZSTD_compressionParameters cParams = params->cParams; - size_t const cctxSize = ZSTD_estimateCCtxSize_advanced(cParams); + size_t const cctxSize = ZSTD_estimateCCtxSize_advanced_opaque(params); size_t const neededSize = sizeof(ZSTD_CDict) + (params->dictContentByRef ? 0 : dictSize) + cctxSize; ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; @@ -3808,11 +3829,9 @@ ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( ptr = cdict+1; } cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize); + params->dictContentByRef = 1; - if (ZSTD_isError( ZSTD_initCDict_internal(cdict, - dict, dictSize, - 1 /* byReference */, params->dictMode, - cParams) )) + if (ZSTD_isError( ZSTD_initCDict_internal_opaque(cdict, dict, dictSize, *params) )) return NULL; return cdict; @@ -3843,12 +3862,13 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, workspace, workspaceSize, dict, dictSize, ¶ms); } - -ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) { +#if 0 +static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) { return ZSTD_getParamsFromCCtx(cdict->refContext); -} +}a +#endif -static ZSTD_CCtx_params ZSTD_getCCtxParamsFromCDict(const ZSTD_CDict* cdict) { +ZSTD_CCtx_params ZSTD_getCCtxParamsFromCDict(const ZSTD_CDict* cdict) { return cdict->refContext->appliedParams; } @@ -3969,6 +3989,7 @@ static size_t ZSTD_resetCStream_internal_opaque( return 0; /* ready to go */ } +#if 0 static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, const ZSTD_CDict* cdict, @@ -3981,16 +4002,17 @@ static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, return ZSTD_resetCStream_internal_opaque(zcs, dict, dictSize, dictMode, cdict, cctxParams, pledgedSrcSize); } +#endif size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) { - ZSTD_parameters params = ZSTD_getParamsFromCCtxParams(zcs->requestedParams); + ZSTD_CCtx_params params = zcs->requestedParams; params.fParams.contentSizeFlag = (pledgedSrcSize > 0); DEBUGLOG(5, "ZSTD_resetCStream"); - if (zcs->requestedParams.compressionLevel != ZSTD_CLEVEL_CUSTOM) { - params.cParams = ZSTD_getCParams(zcs->requestedParams.compressionLevel, pledgedSrcSize, 0 /* dictSize */); + if (params.compressionLevel != ZSTD_CLEVEL_CUSTOM) { + params.cParams = ZSTD_getCParams(params.compressionLevel, pledgedSrcSize, 0 /* dictSize */); } - return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->requestedParams.dictMode, zcs->cdict, params, pledgedSrcSize); + return ZSTD_resetCStream_internal_opaque(zcs, NULL, 0, params.dictMode, zcs->cdict, params, pledgedSrcSize); } size_t ZSTD_initCStream_internal_opaque(ZSTD_CStream* zcs, @@ -4032,12 +4054,12 @@ size_t ZSTD_initCStream_internal_opaque(ZSTD_CStream* zcs, params, pledgedSrcSize); } - +#if 0 /*! ZSTD_initCStream_internal() : * Note : not static, but hidden (not exposed). Used by zstdmt_compress.c * Assumption 1 : params are valid * Assumption 2 : either dict, or cdict, is defined, not both */ -size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, +static size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, const void* dict, size_t dictSize, const ZSTD_CDict* cdict, ZSTD_parameters params, unsigned long long pledgedSrcSize) { @@ -4048,6 +4070,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, return ZSTD_initCStream_internal_opaque(zcs, dict, dictSize, cdict, cctxParams, pledgedSrcSize); } +#endif /* ZSTD_initCStream_usingCDict_advanced() : * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */ @@ -4057,9 +4080,10 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) { /* cannot handle NULL cdict (does not know what to do) */ if (!cdict) return ERROR(dictionary_wrong); - { ZSTD_parameters params = ZSTD_getParamsFromCDict(cdict); + { ZSTD_CCtx_params params = ZSTD_getCCtxParamsFromCDict(cdict); params.fParams = fParams; - return ZSTD_initCStream_internal(zcs, + params.compressionLevel = ZSTD_CLEVEL_CUSTOM; + return ZSTD_initCStream_internal_opaque(zcs, NULL, 0, cdict, params, pledgedSrcSize); } @@ -4076,30 +4100,34 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize) { + ZSTD_CCtx_params cctxParams = zcs->requestedParams; CHECK_F( ZSTD_checkCParams(params.cParams) ); - zcs->requestedParams = ZSTD_makeCCtxParamsFromParams(params); + zcs->requestedParams.cParams = params.cParams; + zcs->requestedParams.fParams = params.fParams; zcs->requestedParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; - return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, pledgedSrcSize); + return ZSTD_initCStream_internal_opaque(zcs, dict, dictSize, NULL, cctxParams, pledgedSrcSize); } size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) { ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); - zcs->requestedParams.compressionLevel = compressionLevel; - return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, 0); + ZSTD_CCtx_params cctxParams = zcs->requestedParams; + cctxParams.cParams = params.cParams; + cctxParams.fParams = params.fParams; + cctxParams.compressionLevel = compressionLevel; + return ZSTD_initCStream_internal_opaque(zcs, dict, dictSize, NULL, cctxParams, 0); } size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize) { ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0); params.fParams.contentSizeFlag = (pledgedSrcSize>0); - return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, params, pledgedSrcSize); + return ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize); } size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) { - ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0); - return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, params, 0); + return ZSTD_initCStream_srcSize(zcs, compressionLevel, 0); } /*====== Compression ======*/ @@ -4272,9 +4300,9 @@ size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuf * expects params to be valid. * must receive dict, or cdict, or none, but not both. * @return : 0, or an error code */ -size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, +size_t ZSTDMT_initCStream_internal_opaque(ZSTDMT_CCtx* zcs, const void* dict, size_t dictSize, const ZSTD_CDict* cdict, - ZSTD_parameters params, unsigned long long pledgedSrcSize); + ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, ZSTD_outBuffer* output, @@ -4290,22 +4318,23 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, if (cctx->streamStage == zcss_init) { const void* const prefix = cctx->prefix; size_t const prefixSize = cctx->prefixSize; - ZSTD_parameters params = ZSTD_getParamsFromCCtxParams(cctx->requestedParams); - if (cctx->requestedParams.compressionLevel != ZSTD_CLEVEL_CUSTOM) - params.cParams = ZSTD_getCParams(cctx->requestedParams.compressionLevel, + ZSTD_CCtx_params params = cctx->requestedParams; + + if (params.compressionLevel != ZSTD_CLEVEL_CUSTOM) + params.cParams = ZSTD_getCParams(params.compressionLevel, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); cctx->prefix = NULL; cctx->prefixSize = 0; /* single usage */ assert(prefix==NULL || cctx->cdict==NULL); /* only one can be set */ #ifdef ZSTD_MULTITHREAD - if (cctx->requestedParams.nbThreads > 1) { - DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", cctx->requestedParams.nbThreads); - CHECK_F( ZSTDMT_initCStream_internal(cctx->mtctx, prefix, prefixSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); + if (params.nbThreads > 1) { + DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", params.nbThreads); + CHECK_F( ZSTDMT_initCStream_internal_opaque(cctx->mtctx, prefix, prefixSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); cctx->streamStage = zcss_load; } else #endif { - CHECK_F( ZSTD_resetCStream_internal(cctx, prefix, prefixSize, cctx->requestedParams.dictMode, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); + CHECK_F( ZSTD_resetCStream_internal_opaque(cctx, prefix, prefixSize, params.dictMode, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); } } /* compression stage */ diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 2eb714e60..ea5828f35 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -806,11 +806,13 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize) { - ZSTD_parameters params = ZSTD_getParamsFromCDict(cdict); + ZSTD_CCtx_params params = ZSTD_getCCtxParamsFromCDict(cdict); if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */ + ZSTDMT_zeroCCtxParams(¶ms); params.fParams = fParams; - return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, cdict, - params, pledgedSrcSize); + + return ZSTDMT_initCStream_internal_opaque(mtctx, NULL, 0 /*dictSize*/, cdict, + params, pledgedSrcSize); } From 6cee6e07e5a7e049527b9a32d5a1386d7debb66f Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 18 Aug 2017 22:48:31 -0700 Subject: [PATCH 012/248] Add internal createCDict function --- lib/compress/zstd_compress.c | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 434f40562..4f10aedf4 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -3731,6 +3731,7 @@ static size_t ZSTD_initCDict_internal_opaque(ZSTD_CDict* cdict, return 0; } +#if 0 static size_t ZSTD_initCDict_internal( ZSTD_CDict* cdict, const void* dictBuffer, size_t dictSize, @@ -3748,11 +3749,52 @@ static size_t ZSTD_initCDict_internal( cdict, dictBuffer, dictSize, cctxParams) ); return 0; } +#endif + +ZSTD_CDict* ZSTD_createCDict_advanced_opaque( + const void* dictBuffer, size_t dictSize, + ZSTD_CCtx_params params, ZSTD_customMem customMem) +{ + DEBUGLOG(5, "ZSTD_createCDict_advanced, mode %u", (U32)dictMode); + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; + + { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); + ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem); + /* Initialize to 0 to preserve semantics */ + ZSTD_frameParameters const fParams = { 0, 0, 0 }; + params.fParams = fParams; + + if (!cdict || !cctx) { + ZSTD_free(cdict, customMem); + ZSTD_freeCCtx(cctx); + return NULL; + } + cdict->refContext = cctx; + + + if (ZSTD_isError( ZSTD_initCDict_internal_opaque( + cdict, + dictBuffer, dictSize, + params) )) { + ZSTD_freeCDict(cdict); + return NULL; + } + return cdict; + } +} + ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference, ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams, ZSTD_customMem customMem) { + ZSTD_CCtx_params cctxParams = ZSTD_makeCCtxParamsFromCParams(cParams); + ZSTD_frameParameters const fParams = { 0, 0, 0 }; + cctxParams.fParams = fParams; + cctxParams.dictMode = dictMode; + cctxParams.dictContentByRef = byReference; + return ZSTD_createCDict_advanced_opaque(dictBuffer, dictSize, cctxParams, customMem); +#if 0 DEBUGLOG(5, "ZSTD_createCDict_advanced, mode %u", (U32)dictMode); if (!customMem.customAlloc ^ !customMem.customFree) return NULL; @@ -3776,6 +3818,7 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, return cdict; } +#endif } ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) From 023b24e6d4491d9aa8ed6aba4ed43cff2ea61b34 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Sun, 20 Aug 2017 22:55:07 -0700 Subject: [PATCH 013/248] Add cctx param tests --- lib/common/zstd_internal.h | 5 +- lib/compress/zstd_compress.c | 230 ++++++++++-------------- lib/compress/zstdmt_compress.c | 4 +- lib/zstd.h | 10 +- programs/Makefile | 3 +- programs/fileio.c | 5 + programs/zstdcli.c | 1 + tests/Makefile | 8 +- tests/fullbench.c | 5 + tests/roundTripCrashOpaque.c | 203 ++++++++++++++++++++++ tests/zstreamtest.c | 309 ++++++++++++++++++++++++++++++++- 11 files changed, 639 insertions(+), 144 deletions(-) create mode 100644 tests/roundTripCrashOpaque.c diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 0da950787..1cccca286 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -246,11 +246,14 @@ struct ZSTD_CCtx_params_s { /* Dictionary */ ZSTD_dictMode_e dictMode; /* select restricting dictionary to "rawContent" or "fullDict" only */ U32 dictContentByRef; - U32 nbThreads; /* Multithreading: used only to set mtctx parameters */ + U32 nbThreads; unsigned jobSize; unsigned overlapSizeLog; + + /* Test parameter */ + U32 testParam; }; typedef struct { diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 4f10aedf4..051a848a5 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -261,6 +261,7 @@ size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned #define ZSTD_CLEVEL_CUSTOM 999 +#if 0 static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx) { if (cctx->requestedParams.compressionLevel==ZSTD_CLEVEL_CUSTOM) return; @@ -269,6 +270,7 @@ static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx) cctx->pledgedSrcSizePlusOne-1, 0); cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; } +#endif ZSTD_CCtx_params* ZSTD_createCCtxParams(void) { @@ -280,6 +282,14 @@ ZSTD_CCtx_params* ZSTD_createCCtxParams(void) return params; } +size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params) +{ + if (!params) { return ERROR(GENERIC); } + memset(params, 0, sizeof(ZSTD_CCtx_params)); + params->compressionLevel = ZSTD_CLEVEL_DEFAULT; + return 0; +} + size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* params, ZSTD_compressionParameters cParams) { @@ -330,102 +340,27 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v switch(param) { - case ZSTD_p_compressionLevel : - if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel(); /* cap max compression level */ + case ZSTD_p_compressionLevel: + case ZSTD_p_windowLog: + case ZSTD_p_hashLog: + case ZSTD_p_chainLog: + case ZSTD_p_searchLog: + case ZSTD_p_minMatch: + case ZSTD_p_targetLength: + case ZSTD_p_compressionStrategy: if (value == 0) return 0; /* special value : 0 means "don't change anything" */ if (cctx->cdict) return ERROR(stage_wrong); - cctx->requestedParams.compressionLevel = value; - return 0; + return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); - case ZSTD_p_windowLog : - DEBUGLOG(5, "setting ZSTD_p_windowLog = %u (cdict:%u)", - value, (cctx->cdict!=NULL)); - if (value == 0) return 0; /* special value : 0 means "don't change anything" */ - if (cctx->cdict) return ERROR(stage_wrong); - CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); - ZSTD_cLevelToCParams(cctx); - cctx->requestedParams.cParams.windowLog = value; - return 0; + case ZSTD_p_contentSizeFlag: + case ZSTD_p_checksumFlag: + case ZSTD_p_dictIDFlag: + return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); - case ZSTD_p_hashLog : - if (value == 0) return 0; /* special value : 0 means "don't change anything" */ - if (cctx->cdict) return ERROR(stage_wrong); - CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); - ZSTD_cLevelToCParams(cctx); - cctx->requestedParams.cParams.hashLog = value; - return 0; - - case ZSTD_p_chainLog : - if (value == 0) return 0; /* special value : 0 means "don't change anything" */ - if (cctx->cdict) return ERROR(stage_wrong); - CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); - ZSTD_cLevelToCParams(cctx); - cctx->requestedParams.cParams.chainLog = value; - return 0; - - case ZSTD_p_searchLog : - if (value == 0) return 0; /* special value : 0 means "don't change anything" */ - if (cctx->cdict) return ERROR(stage_wrong); - CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); - ZSTD_cLevelToCParams(cctx); - cctx->requestedParams.cParams.searchLog = value; - return 0; - - case ZSTD_p_minMatch : - if (value == 0) return 0; /* special value : 0 means "don't change anything" */ - if (cctx->cdict) return ERROR(stage_wrong); - CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); - ZSTD_cLevelToCParams(cctx); - cctx->requestedParams.cParams.searchLength = value; - return 0; - - case ZSTD_p_targetLength : - if (value == 0) return 0; /* special value : 0 means "don't change anything" */ - if (cctx->cdict) return ERROR(stage_wrong); - CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); - ZSTD_cLevelToCParams(cctx); - cctx->requestedParams.cParams.targetLength = value; - return 0; - - case ZSTD_p_compressionStrategy : - if (value == 0) return 0; /* special value : 0 means "don't change anything" */ - if (cctx->cdict) return ERROR(stage_wrong); - CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra); - ZSTD_cLevelToCParams(cctx); - cctx->requestedParams.cParams.strategy = (ZSTD_strategy)value; - return 0; - - case ZSTD_p_contentSizeFlag : - DEBUGLOG(5, "set content size flag = %u", (value>0)); - /* Content size written in frame header _when known_ (default:1) */ - cctx->requestedParams.fParams.contentSizeFlag = value>0; - return 0; - - case ZSTD_p_checksumFlag : - /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ - cctx->requestedParams.fParams.checksumFlag = value>0; - return 0; - - case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ - DEBUGLOG(5, "set dictIDFlag = %u", (value>0)); - cctx->requestedParams.fParams.noDictIDFlag = (value==0); - return 0; - - /* Dictionary parameters */ - case ZSTD_p_dictMode : + case ZSTD_p_dictMode: + case ZSTD_p_refDictContent: if (cctx->cdict) return ERROR(stage_wrong); /* must be set before loading */ - /* restrict dictionary mode, to "rawContent" or "fullDict" only */ - ZSTD_STATIC_ASSERT((U32)ZSTD_dm_fullDict > (U32)ZSTD_dm_rawContent); - if (value > (unsigned)ZSTD_dm_fullDict) - return ERROR(parameter_outOfBound); - cctx->requestedParams.dictMode = (ZSTD_dictMode_e)value; - return 0; - - case ZSTD_p_refDictContent : - if (cctx->cdict) return ERROR(stage_wrong); /* must be set before loading */ - /* dictionary content will be referenced, instead of copied */ - cctx->requestedParams.dictContentByRef = value>0; - return 0; + return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize, * even when referencing into Dictionary content @@ -462,6 +397,11 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v assert(cctx->mtctx != NULL); return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_overlapSectionLog, value); + case ZSTD_p_test : + DEBUGLOG(2, "Setting test parameter = %u", value); + cctx->requestedParams.testParam = (value > 0); + return 0; + default: return ERROR(parameter_unsupported); } } @@ -527,14 +467,18 @@ size_t ZSTD_CCtxParam_setParameter( return 0; case ZSTD_p_contentSizeFlag : + /* Content size written in frame header _when known_ (default:1) */ + DEBUGLOG(5, "set content size flag = %u", (value>0)); params->fParams.contentSizeFlag = value > 0; return 0; case ZSTD_p_checksumFlag : + /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ params->fParams.checksumFlag = value > 0; return 0; case ZSTD_p_dictIDFlag : + DEBUGLOG(5, "set dictIDFlag = %u", (value>0)); params->fParams.noDictIDFlag = (value == 0); return 0; @@ -559,7 +503,7 @@ size_t ZSTD_CCtxParam_setParameter( #ifndef ZSTD_MULTITHREAD if (value > 1) return ERROR(parameter_unsupported); #endif - // Do checks when applying parameters to cctx. + /* Do checks when applying params to cctx */ params->nbThreads = value; return 0; @@ -569,18 +513,57 @@ size_t ZSTD_CCtxParam_setParameter( return 0; case ZSTD_p_overlapSizeLog : + if (params->nbThreads <= 1) { return ERROR(parameter_unsupported); } params->overlapSizeLog = value; return 0; + case ZSTD_p_test : + DEBUGLOG(2, "setting opaque: ZSTD_p_test: %u", value); + params->testParam = (value > 0); + return 0; + default: return ERROR(parameter_unsupported); } } +static void ZSTD_debugPrintCCtxParams(ZSTD_CCtx_params* params) +{ + DEBUGLOG(2, "======CCtxParams======"); + DEBUGLOG(2, "cParams: %u %u %u %u %u %u %u", + params->cParams.windowLog, + params->cParams.chainLog, + params->cParams.hashLog, + params->cParams.searchLog, + params->cParams.searchLength, + params->cParams.targetLength, + params->cParams.strategy); + DEBUGLOG(2, "fParams: %u %u %u", + params->fParams.contentSizeFlag, + params->fParams.checksumFlag, + params->fParams.noDictIDFlag); + DEBUGLOG(2, "cLevel, forceWindow: %u %u", + params->compressionLevel, + params->forceWindow); + DEBUGLOG(2, "dictionary: %u %u", + params->dictMode, + params->dictContentByRef); + DEBUGLOG(2, "multithreading: %u %u %u", + params->nbThreads, + params->jobSize, + params->overlapSizeLog); + DEBUGLOG(2, "testParam: %u", + params->testParam); +} + // This function should probably be updated whenever ZSTD_CCtx_params is updated. ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, ZSTD_CCtx_params* params) { + if (params == NULL) { return ERROR(GENERIC); } if (cctx->cdict) { return ERROR(stage_wrong); } + DEBUGLOG(2, "Applying cctx params\n"); + ZSTD_debugPrintCCtxParams(params); + /* Assume the compression and frame parameters are validated */ cctx->requestedParams.cParams = params->cParams; cctx->requestedParams.fParams = params->fParams; @@ -596,9 +579,14 @@ ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, ZSTD_CCtx_params* /* Set multithreading parameters explicitly */ CHECK_F( ZSTD_CCtx_setParameter(cctx, ZSTD_p_nbThreads, params->nbThreads) ); - CHECK_F( ZSTD_CCtx_setParameter(cctx, ZSTD_p_jobSize, params->jobSize) ); - CHECK_F( ZSTD_CCtx_setParameter( + if (params->nbThreads > 1) { + CHECK_F( ZSTD_CCtx_setParameter(cctx, ZSTD_p_jobSize, params->jobSize) ); + CHECK_F( ZSTD_CCtx_setParameter( cctx, ZSTD_p_overlapSizeLog, params->overlapSizeLog) ); + + } + /* Copy test parameter */ + cctx->requestedParams.testParam = params->testParam; return 0; } @@ -790,8 +778,7 @@ size_t ZSTD_estimateCCtxSize(int compressionLevel) size_t ZSTD_estimateCStreamSize_advanced_opaque(ZSTD_CCtx_params* params) { if (params == NULL) { return 0; } - { - size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced_opaque(params); + { size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced_opaque(params); size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog); size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize; size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; @@ -3265,7 +3252,6 @@ size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) ZSTD_compressionParameters cParams = (cLevel == ZSTD_CLEVEL_CUSTOM) ? cctx->appliedParams.cParams : ZSTD_getCParams(cLevel, 0, 0); - DEBUGLOG(2, "ZSTD_getBlockSize: cLevel %u\n", cLevel); return MIN (ZSTD_BLOCKSIZE_MAX, 1 << cParams.windowLog); } @@ -3485,7 +3471,8 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, return ZSTD_compress_insertDictionary(cctx, dict, dictSize, params.dictMode); } -size_t ZSTD_compressBegin_advanced_opaque(ZSTD_CCtx* cctx, +size_t ZSTD_compressBegin_advanced_opaque( + ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) @@ -3619,11 +3606,12 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, } /* Internal */ -size_t ZSTD_compress_advanced_opaque(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const void* dict,size_t dictSize, - ZSTD_CCtx_params params) +size_t ZSTD_compress_advanced_opaque( + ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + ZSTD_CCtx_params params) { CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL, params, srcSize, ZSTDb_not_buffered) ); @@ -3751,11 +3739,11 @@ static size_t ZSTD_initCDict_internal( } #endif -ZSTD_CDict* ZSTD_createCDict_advanced_opaque( +static ZSTD_CDict* ZSTD_createCDict_advanced_opaque( const void* dictBuffer, size_t dictSize, ZSTD_CCtx_params params, ZSTD_customMem customMem) { - DEBUGLOG(5, "ZSTD_createCDict_advanced, mode %u", (U32)dictMode); + DEBUGLOG(5, "ZSTD_createCDict_advanced_opaque, mode %u", (U32)params.dictMode); if (!customMem.customAlloc ^ !customMem.customFree) return NULL; { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); @@ -3794,31 +3782,6 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, cctxParams.dictMode = dictMode; cctxParams.dictContentByRef = byReference; return ZSTD_createCDict_advanced_opaque(dictBuffer, dictSize, cctxParams, customMem); -#if 0 - DEBUGLOG(5, "ZSTD_createCDict_advanced, mode %u", (U32)dictMode); - if (!customMem.customAlloc ^ !customMem.customFree) return NULL; - - { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); - ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem); - - if (!cdict || !cctx) { - ZSTD_free(cdict, customMem); - ZSTD_freeCCtx(cctx); - return NULL; - } - cdict->refContext = cctx; - - if (ZSTD_isError( ZSTD_initCDict_internal(cdict, - dictBuffer, dictSize, - byReference, dictMode, - cParams) )) { - ZSTD_freeCDict(cdict); - return NULL; - } - - return cdict; - } -#endif } ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) @@ -4064,7 +4027,6 @@ size_t ZSTD_initCStream_internal_opaque(ZSTD_CStream* zcs, ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) { - DEBUGLOG(5, "ZSTD_initCStream_internal"); assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ @@ -4145,9 +4107,9 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, { ZSTD_CCtx_params cctxParams = zcs->requestedParams; CHECK_F( ZSTD_checkCParams(params.cParams) ); - zcs->requestedParams.cParams = params.cParams; - zcs->requestedParams.fParams = params.fParams; - zcs->requestedParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; + cctxParams.cParams = params.cParams; + cctxParams.fParams = params.fParams; + cctxParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; return ZSTD_initCStream_internal_opaque(zcs, dict, dictSize, NULL, cctxParams, pledgedSrcSize); } diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index ea5828f35..1296cd316 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -62,7 +62,7 @@ static unsigned long long GetCurrentClockTimeMicroseconds(void) DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, "Thread took %llu microseconds to acquire mutex %s \n", \ elapsedTime, #mutex); \ } } \ - } else pthread_mutex_lock(mutex); \ + } else { pthread_mutex_lock(mutex); } \ } #else @@ -646,7 +646,7 @@ static size_t ZSTDMT_compress_advanced_opaque( } } /* for (chunkID=0; chunkID dstCapacity) { diff --git a/lib/zstd.h b/lib/zstd.h index 56316160a..eb2a857fe 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -498,6 +498,7 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); * It will also consider src size to be arbitrarily "large", which is worst case. * If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced() can provide a tighter estimation. * ZSTD_estimateCCtxSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + * TODO: ZSTD_estimateCCtxSize_advanced_opaque() * Note : CCtx estimation is only correct for single-threaded compression */ ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced(ZSTD_compressionParameters cParams); @@ -509,6 +510,7 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); * It will also consider src size to be arbitrarily "large", which is worst case. * If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced() can provide a tighter estimation. * ZSTD_estimateCStreamSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + * TODO: ZSTD_estimateCStreamSize_advanced_opaque * Note : CStream estimation is only correct for single-threaded compression. * ZSTD_DStream memory budget depends on window Size. * This information can be passed manually, using ZSTD_estimateDStreamSize, @@ -525,11 +527,10 @@ ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t sr /*! ZSTD_estimate?DictSize() : * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). * ZSTD_estimateCStreamSize_advanced() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced(). + * TODO: ZSTD_estimateCDictSize_advanced_opaque(), can set by reference * Note : dictionary created "byReference" are smaller */ ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference); - -// By reference ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced_opaque(size_t dictSize, ZSTD_CCtx_params* params); ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference); @@ -613,12 +614,11 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( ZSTD_CCtx_params* params); ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); +ZSTDLIB_API size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params); ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createAndInitCCtxParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); ZSTDLIB_API size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* params, ZSTD_compressionParameters cParams); ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); -ZSTDLIB_API - /*! ZSTD_getCParams() : * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. @@ -647,6 +647,7 @@ ZSTDLIB_API size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, const void* dict,size_t dictSize, ZSTD_parameters params); + /*! ZSTD_compress_usingCDict_advanced() : * Same as ZSTD_compress_usingCDict(), with fine-tune control over frame parameters */ ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, @@ -1002,6 +1003,7 @@ typedef enum { /* advanced parameters - may not remain available after API update */ ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize, * even when referencing into Dictionary content (default:0) */ + ZSTD_p_test, } ZSTD_cParameter; diff --git a/programs/Makefile b/programs/Makefile index 2460a091f..a192716a6 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -47,7 +47,8 @@ DEBUGFLAGS = -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ -Wstrict-prototypes -Wundef -Wpointer-arith -Wformat-security \ -Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \ -Wredundant-decls -CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) +ZSTD_DEBUG_FLAGS = -g -DZSTD_DEBUG=2 +CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) $(ZSTD_DEBUG_FLAGS) FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) diff --git a/programs/fileio.c b/programs/fileio.c index 1dd8008e8..b32dd83e0 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -213,6 +213,8 @@ void FIO_setOverlapLog(unsigned overlapLog){ DISPLAYLEVEL(2, "Setting overlapLog is useless in single-thread mode \n"); g_overlapLog = overlapLog; } +static U32 g_testParamFlag = 0; +void FIO_setTestParamFlag(unsigned testParamFlag) { g_testParamFlag = testParamFlag; } /*-************************************* @@ -411,6 +413,9 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel, CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nbThreads, g_nbThreads) ); /* dictionary */ CHECK( ZSTD_CCtx_loadDictionary(ress.cctx, dictBuffer, dictBuffSize) ); + + /* Test */ + CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_test, g_testParamFlag) ); } #elif defined(ZSTD_MULTITHREAD) { ZSTD_parameters params = ZSTD_getParams(cLevel, srcSize, dictBuffSize); diff --git a/programs/zstdcli.c b/programs/zstdcli.c index b1268c1f3..88d4e1524 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -430,6 +430,7 @@ int main(int argCount, const char* argv[]) if (!strcmp(argument, "--keep")) { FIO_setRemoveSrcFile(0); continue; } if (!strcmp(argument, "--rm")) { FIO_setRemoveSrcFile(1); continue; } if (!strcmp(argument, "--priority=rt")) { setRealTimePrio = 1; continue; } + if (!strcmp(argument, "--testParam")) { FIO_setTestParamFlag(1); continue; } #ifdef ZSTD_GZCOMPRESS if (!strcmp(argument, "--format=gzip")) { suffix = GZ_EXTENSION; FIO_setCompressionType(FIO_gzipCompression); continue; } #endif diff --git a/tests/Makefile b/tests/Makefile index 3734f7737..55de2f58a 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -25,7 +25,7 @@ PRGDIR = ../programs PYTHON ?= python3 TESTARTEFACT := versionsTest namespaceTest -DEBUGLEVEL= 1 +DEBUGLEVEL= 2 DEBUGFLAGS= -g -DZSTD_DEBUG=$(DEBUGLEVEL) CPPFLAGS += -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/compress \ -I$(ZSTDDIR)/dictBuilder -I$(ZSTDDIR)/deprecated -I$(PRGDIR) @@ -169,6 +169,12 @@ datagen : $(PRGDIR)/datagen.c datagencli.c roundTripCrash : $(ZSTD_FILES) roundTripCrash.c $(CC) $(FLAGS) $^ -o $@$(EXT) +OPAQUEFILES := $(ZSTD_FILES) $(ZDICT_FILES) roundTripCrashOpaque.c +roundTripCrashOpaque : LDFLAGS += $(MULTITHREAD_CPP) +roundTripCrashOpaque : LDFLAGS += $(MULTITHREAD_LD) +roundTripCrashOpaque : $(OPAQUEFILES) + $(CC) $(FLAGS) $^ -o $@$(EXT) + longmatch : $(ZSTD_FILES) longmatch.c $(CC) $(FLAGS) $^ -o $@$(EXT) diff --git a/tests/fullbench.c b/tests/fullbench.c index 45ef2b6a3..0c41aa3d5 100644 --- a/tests/fullbench.c +++ b/tests/fullbench.c @@ -136,8 +136,10 @@ size_t local_ZSTD_compressStream(void* dst, size_t dstCapacity, void* buff2, con buffIn.src = src; buffIn.size = srcSize; buffIn.pos = 0; + ZSTD_compressStream(g_cstream, &buffOut, &buffIn); ZSTD_endStream(g_cstream, &buffOut); + return buffOut.pos; } @@ -383,11 +385,13 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) const BYTE* ip = dstBuff; const BYTE* iend; size_t frameHeaderSize, cBlockSize; + ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1); /* it would be better to use direct block compression here */ g_cSize = ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1); frameHeaderSize = ZSTD_getFrameHeader(&zfp, dstBuff, ZSTD_frameHeaderSize_min); if (frameHeaderSize==0) frameHeaderSize = ZSTD_frameHeaderSize_min; ip += frameHeaderSize; /* Skip frame Header */ + cBlockSize = ZSTD_getcBlockSize(ip, dstBuffSize, &bp); /* Get 1st block type */ if (bp.blockType != bt_compressed) { DISPLAY("ZSTD_decodeSeqHeaders : impossible to test on this sample (not compressible)\n"); @@ -395,6 +399,7 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) } iend = ip + ZSTD_blockHeaderSize + cBlockSize; /* End of first block */ ip += ZSTD_blockHeaderSize; /* skip block header */ + ZSTD_decompressBegin(g_zdc); ip += ZSTD_decodeLiteralsBlock(g_zdc, ip, iend-ip); /* skip literal segment */ g_cSize = iend-ip; diff --git a/tests/roundTripCrashOpaque.c b/tests/roundTripCrashOpaque.c new file mode 100644 index 000000000..f9b6e7f83 --- /dev/null +++ b/tests/roundTripCrashOpaque.c @@ -0,0 +1,203 @@ +/** + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +/* + This program takes a file in input, + performs a zstd round-trip test (compression - decompress) + compares the result with original + and generates a crash (double free) on corruption detection. +*/ + +/*=========================================== +* Dependencies +*==========================================*/ +#include /* size_t */ +#include /* malloc, free, exit */ +#include /* fprintf */ +#include /* stat */ +#include /* stat */ +#include "xxhash.h" + +#define ZSTD_STATIC_LINKING_ONLY +#include "zstd.h" + +/*=========================================== +* Macros +*==========================================*/ +#define MIN(a,b) ( (a) < (b) ? (a) : (b) ) + +#define CHECK_Z(f) { \ + size_t const err = f; \ + if (ZSTD_isError(err)) { \ + fprintf(stderr, \ + "Error=> %s: %s", \ + #f, ZSTD_getErrorName(err)); \ + exit(1); \ +} } + + +/** roundTripTest() : +* Compresses `srcBuff` into `compressedBuff`, +* then decompresses `compressedBuff` into `resultBuff`. +* @return : result of decompression, which should be == `srcSize` +* or an error code if either compression or decompression fails. +* Note : `compressedBuffCapacity` should be `>= ZSTD_compressBound(srcSize)` +* for compression to be guaranteed to work */ +static size_t roundTripTest(void* resultBuff, size_t resultBuffCapacity, + void* compressedBuff, size_t compressedBuffCapacity, + const void* srcBuff, size_t srcBuffSize) +{ + ZSTD_CCtx* const cctx = ZSTD_createCCtx(); + ZSTD_CCtx_params* const cctxParams = ZSTD_createCCtxParams(); + ZSTD_inBuffer inBuffer = { srcBuff, srcBuffSize, 0 }; + ZSTD_outBuffer outBuffer = {compressedBuff, compressedBuffCapacity, 0 }; + + ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_compressionLevel, 1); + ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_test, 1); + + ZSTD_CCtx_applyCCtxParams(cctx, cctxParams); + + CHECK_Z (ZSTD_compress_generic(cctx, &outBuffer, &inBuffer, ZSTD_e_end) ); + + ZSTD_freeCCtxParams(cctxParams); + ZSTD_freeCCtx(cctx); + + return ZSTD_decompress(resultBuff, resultBuffCapacity, compressedBuff, outBuffer.pos); +} + + +static size_t checkBuffers(const void* buff1, const void* buff2, size_t buffSize) +{ + const char* ip1 = (const char*)buff1; + const char* ip2 = (const char*)buff2; + size_t pos; + + for (pos=0; pos= `fileSize` */ +static void loadFile(void* buffer, const char* fileName, size_t fileSize) +{ + FILE* const f = fopen(fileName, "rb"); + if (isDirectory(fileName)) { + fprintf(stderr, "Ignoring %s directory \n", fileName); + exit(2); + } + if (f==NULL) { + fprintf(stderr, "Impossible to open %s \n", fileName); + exit(3); + } + { size_t const readSize = fread(buffer, 1, fileSize, f); + if (readSize != fileSize) { + fprintf(stderr, "Error reading %s \n", fileName); + exit(5); + } } + fclose(f); +} + + +static void fileCheck(const char* fileName) +{ + size_t const fileSize = getFileSize(fileName); + void* buffer = malloc(fileSize); + if (!buffer) { + fprintf(stderr, "not enough memory \n"); + exit(4); + } + loadFile(buffer, fileName, fileSize); + roundTripCheck(buffer, fileSize); + free (buffer); +} + +int main(int argCount, const char** argv) { + if (argCount < 2) { + fprintf(stderr, "Error : no argument : need input file \n"); + exit(9); + } + fileCheck(argv[1]); + fprintf(stderr, "no pb detected\n"); + return 0; +} diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 3e551e331..0281a406d 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1494,6 +1494,309 @@ _output_error: goto _cleanup; } +static int fuzzerTests_newAPI_opaque(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests) +{ + U32 const maxSrcLog = bigTests ? 24 : 22; + static const U32 maxSampleLog = 19; + size_t const srcBufferSize = (size_t)1<= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); } + else { DISPLAYUPDATE(2, "\r%6u ", testNb); } + FUZ_rand(&coreSeed); + lseed = coreSeed ^ prime32; + + /* states full reset (deliberately not synchronized) */ + /* some issues can only happen when reusing states */ + if ((FUZ_rand(&lseed) & 0xFF) == 131) { + DISPLAYLEVEL(5, "Creating new context \n"); + ZSTD_freeCCtx(zc); + zc = ZSTD_createCCtx(); + CHECK(zc==NULL, "ZSTD_createCCtx allocation error"); + resetAllowed=0; + } + if ((FUZ_rand(&lseed) & 0xFF) == 132) { + ZSTD_freeDStream(zd); + zd = ZSTD_createDStream(); + CHECK(zd==NULL, "ZSTD_createDStream allocation error"); + ZSTD_initDStream_usingDict(zd, NULL, 0); /* ensure at least one init */ + } + + /* srcBuffer selection [0-4] */ + { U32 buffNb = FUZ_rand(&lseed) & 0x7F; + if (buffNb & 7) buffNb=2; /* most common : compressible (P) */ + else { + buffNb >>= 3; + if (buffNb & 7) { + const U32 tnb[2] = { 1, 3 }; /* barely/highly compressible */ + buffNb = tnb[buffNb >> 3]; + } else { + const U32 tnb[2] = { 0, 4 }; /* not compressible / sparse */ + buffNb = tnb[buffNb >> 3]; + } } + srcBuffer = cNoiseBuffer[buffNb]; + } + + /* compression init */ + CHECK_Z( ZSTD_CCtx_loadDictionary(zc, NULL, 0) ); /* cancel previous dict /*/ + if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */ + && oldTestLog /* at least one test happened */ && resetAllowed) { + maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2); + if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1; + { int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1; + CHECK_Z (ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_compressionLevel, compressionLevel)); + } + } else { + U32 const testLog = FUZ_rand(&lseed) % maxSrcLog; + U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog; + U32 const cLevelCandidate = (FUZ_rand(&lseed) % + (ZSTD_maxCLevel() - + (MAX(testLog, dictLog) / 3))) + + 1; + U32 const cLevel = MIN(cLevelCandidate, cLevelMax); + maxTestSize = FUZ_rLogLength(&lseed, testLog); + oldTestLog = testLog; + /* random dictionary selection */ + dictSize = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0; + { size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize); + dict = srcBuffer + dictStart; + if (!dictSize) dict=NULL; + } + { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize; + ZSTD_compressionParameters cParams = ZSTD_getCParams(cLevel, pledgedSrcSize, dictSize); + + /* mess with compression parameters */ + cParams.windowLog += (FUZ_rand(&lseed) & 3) - 1; + cParams.hashLog += (FUZ_rand(&lseed) & 3) - 1; + cParams.chainLog += (FUZ_rand(&lseed) & 3) - 1; + cParams.searchLog += (FUZ_rand(&lseed) & 3) - 1; + cParams.searchLength += (FUZ_rand(&lseed) & 3) - 1; + cParams.targetLength = (U32)(cParams.targetLength * (0.5 + ((double)(FUZ_rand(&lseed) & 127) / 128))); + cParams = ZSTD_adjustCParams(cParams, 0, 0); + + if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_windowLog, cParams.windowLog) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_hashLog, cParams.hashLog) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_chainLog, cParams.chainLog) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_searchLog, cParams.searchLog) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_minMatch, cParams.searchLength) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_targetLength, cParams.targetLength) ); + + /* unconditionally set, to be sync with decoder */ + /* mess with frame parameters */ + if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_checksumFlag, FUZ_rand(&lseed) & 1) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_dictIDFlag, FUZ_rand(&lseed) & 1) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_contentSizeFlag, FUZ_rand(&lseed) & 1) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) ); + DISPLAYLEVEL(5, "pledgedSrcSize : %u \n", (U32)pledgedSrcSize); + + if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_refDictContent, FUZ_rand(&lseed) & 1) ); + /* multi-threading parameters */ + { U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1; + U32 const nbThreads = MIN(nbThreadsCandidate, nbThreadsMax); + CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_nbThreads, nbThreads) ); + if (nbThreads > 1) { + U32 const jobLog = FUZ_rand(&lseed) % (testLog+1); + CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_overlapSizeLog, FUZ_rand(&lseed) % 10) ); + CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_jobSize, (U32)FUZ_rLogLength(&lseed, jobLog)) ); + } + } + + if (FUZ_rand(&lseed) & 1) CHECK_Z (ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_forceMaxWindow, FUZ_rand(&lseed) & 1) ); + + if (FUZ_rand(&lseed) & 1) CHECK_Z (ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_test, FUZ_rand(&lseed) & 1) ); + + + /* Apply parameters */ + + CHECK_Z (ZSTD_CCtx_applyCCtxParams(zc, cctxParams) ); + + if (FUZ_rand(&lseed) & 1) { + CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) ); + if (dict && dictSize) { + /* test that compression parameters are rejected (correctly) after loading a non-NULL dictionary */ + size_t const setError = ZSTD_CCtx_applyCCtxParams(zc, cctxParams); + CHECK(!ZSTD_isError(setError), "ZSTD_CCtx_applyCCtxParams should have failed"); + } } else { + CHECK_Z( ZSTD_CCtx_refPrefix(zc, dict, dictSize) ); + } + } } + + /* multi-segments compression test */ + XXH64_reset(&xxhState, 0); + { ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ; + for (cSize=0, totalTestSize=0 ; (totalTestSize < maxTestSize) ; ) { + /* compress random chunks into randomly sized dst buffers */ + size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog); + size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize); + size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize); + size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1); + size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize); + ZSTD_EndDirective const flush = (FUZ_rand(&lseed) & 15) ? ZSTD_e_continue : ZSTD_e_flush; + ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 }; + outBuff.size = outBuff.pos + dstBuffSize; + + CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, flush) ); + DISPLAYLEVEL(5, "compress consumed %u bytes (total : %u) \n", + (U32)inBuff.pos, (U32)(totalTestSize + inBuff.pos)); + + XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos); + memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos); + totalTestSize += inBuff.pos; + } + + /* final frame epilogue */ + { size_t remainingToFlush = (size_t)(-1); + while (remainingToFlush) { + ZSTD_inBuffer inBuff = { NULL, 0, 0 }; + size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1); + size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize); + outBuff.size = outBuff.pos + adjustedDstSize; + DISPLAYLEVEL(5, "End-flush into dst buffer of size %u \n", (U32)adjustedDstSize); + remainingToFlush = ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end); + CHECK(ZSTD_isError(remainingToFlush), + "ZSTD_compress_generic w/ ZSTD_e_end error : %s", + ZSTD_getErrorName(remainingToFlush) ); + } } + crcOrig = XXH64_digest(&xxhState); + cSize = outBuff.pos; + DISPLAYLEVEL(5, "Frame completed : %u bytes \n", (U32)cSize); + } + + /* multi - fragments decompression test */ + if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) { + DISPLAYLEVEL(5, "resetting DCtx (dict:%08X) \n", (U32)(size_t)dict); + CHECK_Z( ZSTD_resetDStream(zd) ); + } else { + DISPLAYLEVEL(5, "using dict of size %u \n", (U32)dictSize); + CHECK_Z( ZSTD_initDStream_usingDict(zd, dict, dictSize) ); + } + { size_t decompressionResult = 1; + ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 }; + ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 }; + for (totalGenSize = 0 ; decompressionResult ; ) { + size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog); + size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog); + size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize); + inBuff.size = inBuff.pos + readCSrcSize; + outBuff.size = inBuff.pos + dstBuffSize; + DISPLAYLEVEL(5, "ZSTD_decompressStream input %u bytes (pos:%u/%u)\n", + (U32)readCSrcSize, (U32)inBuff.pos, (U32)cSize); + decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff); + CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult)); + DISPLAYLEVEL(5, "inBuff.pos = %u \n", (U32)readCSrcSize); + } + CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (U32)outBuff.pos, (U32)totalTestSize); + CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (U32)inBuff.pos, (U32)cSize); + { U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0); + if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize); + CHECK (crcDest!=crcOrig, "decompressed data corrupted"); + } } + + /*===== noisy/erroneous src decompression test =====*/ + + /* add some noise */ + { U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2; + U32 nn; for (nn=0; nn Date: Mon, 21 Aug 2017 01:59:08 -0700 Subject: [PATCH 014/248] Disable tests and refactor --- lib/common/zstd_internal.h | 18 ++- lib/compress/zstd_compress.c | 148 ++++++++---------- lib/compress/zstdmt_compress.c | 5 +- lib/compress/zstdmt_compress.h | 9 -- lib/zstd.h | 14 +- programs/Makefile | 3 +- programs/fileio.c | 6 +- programs/fileio.h | 3 + programs/zstdcli.c | 2 + tests/Makefile | 9 +- ...TripCrashOpaque.c => cctxParamRoundTrip.c} | 5 +- tests/fullbench.c | 5 - tests/zstreamtest.c | 4 +- 13 files changed, 102 insertions(+), 129 deletions(-) rename tests/{roundTripCrashOpaque.c => cctxParamRoundTrip.c} (98%) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 1cccca286..8b8419a4c 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -221,6 +221,7 @@ typedef struct seqDef_s { U16 matchLength; } seqDef; + typedef struct { seqDef* sequencesStart; seqDef* sequences; @@ -240,7 +241,6 @@ struct ZSTD_CCtx_params_s { ZSTD_frameParameters fParams; int compressionLevel; - U32 forceWindow; /* force back-references to respect limit of 1<seqStore); } -#if 0 -// TODO: get rid of this function -static ZSTD_parameters ZSTD_getParamsFromCCtxParams(const ZSTD_CCtx_params cctxParams) -{ - ZSTD_parameters params; - params.cParams = cctxParams.cParams; - params.fParams = cctxParams.fParams; - return params; -} -#endif -#if 0 -// TODO: get rid of this function too -static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromParams(ZSTD_parameters params) { - ZSTD_CCtx_params cctxParams; - memset(&cctxParams, 0, sizeof(ZSTD_CCtx_params)); - cctxParams.cParams = params.cParams; - cctxParams.fParams = params.fParams; - return cctxParams; -} -#endif - -// TODO: get rid of this function too +/* TODO: get rid of this function if possible*/ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( ZSTD_compressionParameters cParams) { @@ -234,12 +220,6 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( cctxParams.cParams = cParams; return cctxParams; } -#if 0 -// TODO: get rid of this function -static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { - return ZSTD_getParamsFromCCtxParams(cctx->appliedParams); -} -#endif /* older variant; will be deprecated */ size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value) @@ -261,7 +241,6 @@ size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned #define ZSTD_CLEVEL_CUSTOM 999 -#if 0 static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx) { if (cctx->requestedParams.compressionLevel==ZSTD_CLEVEL_CUSTOM) return; @@ -270,7 +249,6 @@ static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx) cctx->pledgedSrcSizePlusOne-1, 0); cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; } -#endif ZSTD_CCtx_params* ZSTD_createCCtxParams(void) { @@ -290,27 +268,15 @@ size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params) return 0; } -size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* params, - ZSTD_compressionParameters cParams) +size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) { - memset(params, 0, sizeof(ZSTD_CCtx_params)); - params->cParams = cParams; - params->compressionLevel = ZSTD_CLEVEL_CUSTOM; + memset(cctxParams, 0, sizeof(ZSTD_CCtx_params)); + cctxParams->cParams = params.cParams; + cctxParams->fParams = params.fParams; + cctxParams->compressionLevel = ZSTD_CLEVEL_CUSTOM; return 0; } -ZSTD_CCtx_params* ZSTD_createAndInitCCtxParams( - int compressionLevel, unsigned long long estimatedSrcSize, - size_t dictSize) -{ - ZSTD_CCtx_params* params = ZSTD_createCCtxParams(); - if (params == NULL) { return NULL; } - ZSTD_initCCtxParams(params, ZSTD_getCParams( - compressionLevel, estimatedSrcSize, dictSize)); - params->compressionLevel = ZSTD_CLEVEL_CUSTOM; - return params; -} - size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) { if (params == NULL) { return 0; } @@ -318,8 +284,6 @@ size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) return 0; } - - static void ZSTD_cLevelToCCtxParams(ZSTD_CCtx_params* params) { if (params->compressionLevel == ZSTD_CLEVEL_CUSTOM) return; @@ -341,6 +305,10 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v switch(param) { case ZSTD_p_compressionLevel: + if (value == 0) return 0; + if (cctx->cdict) return ERROR(stage_wrong); + return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); + case ZSTD_p_windowLog: case ZSTD_p_hashLog: case ZSTD_p_chainLog: @@ -350,6 +318,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v case ZSTD_p_compressionStrategy: if (value == 0) return 0; /* special value : 0 means "don't change anything" */ if (cctx->cdict) return ERROR(stage_wrong); + ZSTD_cLevelToCParams(cctx); return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); case ZSTD_p_contentSizeFlag: @@ -396,11 +365,12 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v if (cctx->requestedParams.nbThreads <= 1) return ERROR(parameter_unsupported); assert(cctx->mtctx != NULL); return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_overlapSectionLog, value); - +#if 0 case ZSTD_p_test : DEBUGLOG(2, "Setting test parameter = %u", value); cctx->requestedParams.testParam = (value > 0); return 0; +#endif default: return ERROR(parameter_unsupported); } @@ -477,12 +447,13 @@ size_t ZSTD_CCtxParam_setParameter( params->fParams.checksumFlag = value > 0; return 0; - case ZSTD_p_dictIDFlag : + case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ DEBUGLOG(5, "set dictIDFlag = %u", (value>0)); params->fParams.noDictIDFlag = (value == 0); return 0; case ZSTD_p_dictMode : + /* restrict dictionary mode to "rawContent" or "fullDict" only */ ZSTD_STATIC_ASSERT((U32)ZSTD_dm_fullDict > (U32)ZSTD_dm_rawContent); if (value > (unsigned)ZSTD_dm_fullDict) { return ERROR(parameter_outOfBound); @@ -491,6 +462,7 @@ size_t ZSTD_CCtxParam_setParameter( return 0; case ZSTD_p_refDictContent : + /* dictionary content will be referenced, instead of copied */ params->dictContentByRef = value > 0; return 0; @@ -516,16 +488,18 @@ size_t ZSTD_CCtxParam_setParameter( if (params->nbThreads <= 1) { return ERROR(parameter_unsupported); } params->overlapSizeLog = value; return 0; - +#if 0 case ZSTD_p_test : DEBUGLOG(2, "setting opaque: ZSTD_p_test: %u", value); params->testParam = (value > 0); return 0; +#endif default: return ERROR(parameter_unsupported); } } +#if 0 static void ZSTD_debugPrintCCtxParams(ZSTD_CCtx_params* params) { DEBUGLOG(2, "======CCtxParams======"); @@ -551,19 +525,24 @@ static void ZSTD_debugPrintCCtxParams(ZSTD_CCtx_params* params) params->nbThreads, params->jobSize, params->overlapSizeLog); +#if 0 DEBUGLOG(2, "testParam: %u", params->testParam); +#endif } +#endif -// This function should probably be updated whenever ZSTD_CCtx_params is updated. -ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, ZSTD_CCtx_params* params) +/** + * This function should be updated whenever ZSTD_CCtx_params is updated. + * Parameters are copied manually before the dictionary is loaded. + * The multithreading parameters jobSize and overlapSizeLog are set only if + * nbThreads >= 1. + */ +size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, ZSTD_CCtx_params* params) { if (params == NULL) { return ERROR(GENERIC); } if (cctx->cdict) { return ERROR(stage_wrong); } - DEBUGLOG(2, "Applying cctx params\n"); - ZSTD_debugPrintCCtxParams(params); - /* Assume the compression and frame parameters are validated */ cctx->requestedParams.cParams = params->cParams; cctx->requestedParams.fParams = params->fParams; @@ -585,8 +564,10 @@ ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, ZSTD_CCtx_params* cctx, ZSTD_p_overlapSizeLog, params->overlapSizeLog) ); } - /* Copy test parameter */ +#if 0 + /* Copy test parameter */ cctx->requestedParams.testParam = params->testParam; +#endif return 0; } @@ -3247,7 +3228,6 @@ size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) { - // TODO: Applied params compression level okay? Gets overwritten U32 const cLevel = cctx->appliedParams.compressionLevel; ZSTD_compressionParameters cParams = (cLevel == ZSTD_CLEVEL_CUSTOM) ? cctx->appliedParams.cParams : @@ -3710,7 +3690,8 @@ static size_t ZSTD_initCDict_internal_opaque(ZSTD_CDict* cdict, } cdict->dictContentSize = dictSize; - /* Frame parameters should be zero? */ + /* TODO: do the frame parameters need to be zero? + * does nbThreads need to be zero? */ CHECK_F( ZSTD_compressBegin_internal(cdict->refContext, cdict->dictContent, dictSize, NULL, @@ -3748,9 +3729,6 @@ static ZSTD_CDict* ZSTD_createCDict_advanced_opaque( { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem); - /* Initialize to 0 to preserve semantics */ - ZSTD_frameParameters const fParams = { 0, 0, 0 }; - params.fParams = fParams; if (!cdict || !cctx) { ZSTD_free(cdict, customMem); @@ -3759,7 +3737,6 @@ static ZSTD_CDict* ZSTD_createCDict_advanced_opaque( } cdict->refContext = cctx; - if (ZSTD_isError( ZSTD_initCDict_internal_opaque( cdict, dictBuffer, dictSize, @@ -3777,8 +3754,6 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_customMem customMem) { ZSTD_CCtx_params cctxParams = ZSTD_makeCCtxParamsFromCParams(cParams); - ZSTD_frameParameters const fParams = { 0, 0, 0 }; - cctxParams.fParams = fParams; cctxParams.dictMode = dictMode; cctxParams.dictContentByRef = byReference; return ZSTD_createCDict_advanced_opaque(dictBuffer, dictSize, cctxParams, customMem); @@ -3837,6 +3812,7 @@ ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize); params->dictContentByRef = 1; + /* What if nbThreads > 1? */ if (ZSTD_isError( ZSTD_initCDict_internal_opaque(cdict, dict, dictSize, *params) )) return NULL; @@ -3970,11 +3946,10 @@ size_t ZSTD_CStreamOutSize(void) static size_t ZSTD_resetCStream_internal_opaque( ZSTD_CStream* zcs, - const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, + const void* dict, size_t dictSize, const ZSTD_CDict* cdict, ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) { - params.dictMode = dictMode; DEBUGLOG(4, "ZSTD_resetCStream_internal"); /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); @@ -4004,8 +3979,7 @@ static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, ZSTD_CCtx_params cctxParams = zcs->requestedParams; cctxParams.cParams = params.cParams; cctxParams.fParams = params.fParams; - cctxParams.dictMode = dictMode; - return ZSTD_resetCStream_internal_opaque(zcs, dict, dictSize, dictMode, + return ZSTD_resetCStream_internal_opaque(zcs, dict, dictSize, cdict, cctxParams, pledgedSrcSize); } #endif @@ -4018,14 +3992,15 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) if (params.compressionLevel != ZSTD_CLEVEL_CUSTOM) { params.cParams = ZSTD_getCParams(params.compressionLevel, pledgedSrcSize, 0 /* dictSize */); } - return ZSTD_resetCStream_internal_opaque(zcs, NULL, 0, params.dictMode, zcs->cdict, params, pledgedSrcSize); + return ZSTD_resetCStream_internal_opaque(zcs, NULL, 0, zcs->cdict, params, pledgedSrcSize); } -size_t ZSTD_initCStream_internal_opaque(ZSTD_CStream* zcs, - const void* dict, size_t dictSize, - const ZSTD_CDict* cdict, - ZSTD_CCtx_params params, - unsigned long long pledgedSrcSize) +size_t ZSTD_initCStream_internal_opaque( + ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + const ZSTD_CDict* cdict, + ZSTD_CCtx_params params, + unsigned long long pledgedSrcSize) { assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ @@ -4038,8 +4013,8 @@ size_t ZSTD_initCStream_internal_opaque(ZSTD_CStream* zcs, } ZSTD_freeCDict(zcs->cdictLocal); zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, - zcs->requestedParams.dictContentByRef, - zcs->requestedParams.dictMode, + params.dictContentByRef, + params.dictMode, params.cParams, zcs->customMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); @@ -4055,8 +4030,7 @@ size_t ZSTD_initCStream_internal_opaque(ZSTD_CStream* zcs, zcs->requestedParams = params; return ZSTD_resetCStream_internal_opaque( - zcs, NULL, 0, zcs->requestedParams.dictMode, zcs->cdict, - params, pledgedSrcSize); + zcs, NULL, 0, zcs->cdict, params, pledgedSrcSize); } #if 0 @@ -4339,7 +4313,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, } else #endif { - CHECK_F( ZSTD_resetCStream_internal_opaque(cctx, prefix, prefixSize, params.dictMode, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); + CHECK_F( ZSTD_resetCStream_internal_opaque(cctx, prefix, prefixSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); } } /* compression stage */ diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 1296cd316..76a062f04 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -186,6 +186,10 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf) ZSTD_free(buf.start, bufPool->cMem); } +/** + * TODO + * Resets parameters to zero for jobs? + */ static void ZSTDMT_zeroCCtxParams(ZSTD_CCtx_params* params) { params->forceWindow = 0; @@ -778,7 +782,6 @@ size_t ZSTDMT_initCStream_internal_opaque( } - /** ZSTDMT_initCStream_internal() : * internal usage only */ size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, diff --git a/lib/compress/zstdmt_compress.h b/lib/compress/zstdmt_compress.h index 0b478b735..843a240aa 100644 --- a/lib/compress/zstdmt_compress.h +++ b/lib/compress/zstdmt_compress.h @@ -69,15 +69,6 @@ ZSTDLIB_API size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, const ZSTD_CDict* cdict, ZSTD_parameters const params, unsigned overlapLog); -#if 0 -ZSTDLIB_API size_t ZSTDMT_compress_advanced_opaque( - ZSTDMT_CCtx* mtctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const ZSTD_CDict* cdict, - ZSTD_CCtx_params* const params, - unsigned overlapLog); -#endif ZSTDLIB_API size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx, const void* dict, size_t dictSize, /* dict can be released after init, a local copy is preserved within zcs */ diff --git a/lib/zstd.h b/lib/zstd.h index eb2a857fe..f02f28c82 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -510,7 +510,7 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); * It will also consider src size to be arbitrarily "large", which is worst case. * If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced() can provide a tighter estimation. * ZSTD_estimateCStreamSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - * TODO: ZSTD_estimateCStreamSize_advanced_opaque + * TODO: ZSTD_estimateCStreamSize_advanced_opaque() * Note : CStream estimation is only correct for single-threaded compression. * ZSTD_DStream memory budget depends on window Size. * This information can be passed manually, using ZSTD_estimateDStreamSize, @@ -527,7 +527,7 @@ ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t sr /*! ZSTD_estimate?DictSize() : * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). * ZSTD_estimateCStreamSize_advanced() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced(). - * TODO: ZSTD_estimateCDictSize_advanced_opaque(), can set by reference + * TODO: ZSTD_estimateCDictSize_advanced_opaque() * Note : dictionary created "byReference" are smaller */ ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference); @@ -615,11 +615,9 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); ZSTDLIB_API size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params); -ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createAndInitCCtxParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); -ZSTDLIB_API size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* params, ZSTD_compressionParameters cParams); +ZSTDLIB_API size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); - /*! ZSTD_getCParams() : * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. * `estimatedSrcSize` value is optional, select 0 if not known */ @@ -647,7 +645,6 @@ ZSTDLIB_API size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, const void* dict,size_t dictSize, ZSTD_parameters params); - /*! ZSTD_compress_usingCDict_advanced() : * Same as ZSTD_compress_usingCDict(), with fine-tune control over frame parameters */ ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, @@ -1003,7 +1000,9 @@ typedef enum { /* advanced parameters - may not remain available after API update */ ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize, * even when referencing into Dictionary content (default:0) */ +#if 0 ZSTD_p_test, +#endif } ZSTD_cParameter; @@ -1014,8 +1013,9 @@ typedef enum { * @result : 0, or an error code (which can be tested with ZSTD_isError()). */ ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value); +/* TODO */ ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value); - +/* TODO */ ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, ZSTD_CCtx_params* params); /*! ZSTD_CCtx_setPledgedSrcSize() : diff --git a/programs/Makefile b/programs/Makefile index a192716a6..2460a091f 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -47,8 +47,7 @@ DEBUGFLAGS = -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ -Wstrict-prototypes -Wundef -Wpointer-arith -Wformat-security \ -Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \ -Wredundant-decls -ZSTD_DEBUG_FLAGS = -g -DZSTD_DEBUG=2 -CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) $(ZSTD_DEBUG_FLAGS) +CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) diff --git a/programs/fileio.c b/programs/fileio.c index b32dd83e0..1fb249d6b 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -213,9 +213,10 @@ void FIO_setOverlapLog(unsigned overlapLog){ DISPLAYLEVEL(2, "Setting overlapLog is useless in single-thread mode \n"); g_overlapLog = overlapLog; } +#if 0 static U32 g_testParamFlag = 0; void FIO_setTestParamFlag(unsigned testParamFlag) { g_testParamFlag = testParamFlag; } - +#endif /*-************************************* * Functions @@ -413,9 +414,10 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel, CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nbThreads, g_nbThreads) ); /* dictionary */ CHECK( ZSTD_CCtx_loadDictionary(ress.cctx, dictBuffer, dictBuffSize) ); - +#if 0 /* Test */ CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_test, g_testParamFlag) ); +#endif } #elif defined(ZSTD_MULTITHREAD) { ZSTD_parameters params = ZSTD_getParams(cLevel, srcSize, dictBuffSize); diff --git a/programs/fileio.h b/programs/fileio.h index 9d9167df9..497e122e1 100644 --- a/programs/fileio.h +++ b/programs/fileio.h @@ -56,6 +56,9 @@ void FIO_setMemLimit(unsigned memLimit); void FIO_setNbThreads(unsigned nbThreads); void FIO_setBlockSize(unsigned blockSize); void FIO_setOverlapLog(unsigned overlapLog); +#if 0 +void FIO_setTestParamFlag(unsigned testParamFlag); +#endif /*-************************************* diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 88d4e1524..5e95e4268 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -430,7 +430,9 @@ int main(int argCount, const char* argv[]) if (!strcmp(argument, "--keep")) { FIO_setRemoveSrcFile(0); continue; } if (!strcmp(argument, "--rm")) { FIO_setRemoveSrcFile(1); continue; } if (!strcmp(argument, "--priority=rt")) { setRealTimePrio = 1; continue; } +#if 0 if (!strcmp(argument, "--testParam")) { FIO_setTestParamFlag(1); continue; } +#endif #ifdef ZSTD_GZCOMPRESS if (!strcmp(argument, "--format=gzip")) { suffix = GZ_EXTENSION; FIO_setCompressionType(FIO_gzipCompression); continue; } #endif diff --git a/tests/Makefile b/tests/Makefile index 55de2f58a..e815f5850 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -25,7 +25,7 @@ PRGDIR = ../programs PYTHON ?= python3 TESTARTEFACT := versionsTest namespaceTest -DEBUGLEVEL= 2 +DEBUGLEVEL= 1 DEBUGFLAGS= -g -DZSTD_DEBUG=$(DEBUGLEVEL) CPPFLAGS += -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/compress \ -I$(ZSTDDIR)/dictBuilder -I$(ZSTDDIR)/deprecated -I$(PRGDIR) @@ -169,10 +169,9 @@ datagen : $(PRGDIR)/datagen.c datagencli.c roundTripCrash : $(ZSTD_FILES) roundTripCrash.c $(CC) $(FLAGS) $^ -o $@$(EXT) -OPAQUEFILES := $(ZSTD_FILES) $(ZDICT_FILES) roundTripCrashOpaque.c -roundTripCrashOpaque : LDFLAGS += $(MULTITHREAD_CPP) -roundTripCrashOpaque : LDFLAGS += $(MULTITHREAD_LD) -roundTripCrashOpaque : $(OPAQUEFILES) +cctxParamRoundTrip : LDFLAGS += $(MULTITHREAD_CPP) +cctxParamRoundTrip : LDFLAGS += $(MULTITHREAD_LD) +cctxParamRoundTrip : $(ZSTD_FILES) cctxParamRoundTrip.c $(CC) $(FLAGS) $^ -o $@$(EXT) longmatch : $(ZSTD_FILES) longmatch.c diff --git a/tests/roundTripCrashOpaque.c b/tests/cctxParamRoundTrip.c similarity index 98% rename from tests/roundTripCrashOpaque.c rename to tests/cctxParamRoundTrip.c index f9b6e7f83..45a57a151 100644 --- a/tests/roundTripCrashOpaque.c +++ b/tests/cctxParamRoundTrip.c @@ -38,13 +38,16 @@ fprintf(stderr, \ "Error=> %s: %s", \ #f, ZSTD_getErrorName(err)); \ - exit(1); \ + crash(1); \ } } /** roundTripTest() : * Compresses `srcBuff` into `compressedBuff`, * then decompresses `compressedBuff` into `resultBuff`. +* +* Parameters are currently set manually. +* * @return : result of decompression, which should be == `srcSize` * or an error code if either compression or decompression fails. * Note : `compressedBuffCapacity` should be `>= ZSTD_compressBound(srcSize)` diff --git a/tests/fullbench.c b/tests/fullbench.c index 0c41aa3d5..45ef2b6a3 100644 --- a/tests/fullbench.c +++ b/tests/fullbench.c @@ -136,10 +136,8 @@ size_t local_ZSTD_compressStream(void* dst, size_t dstCapacity, void* buff2, con buffIn.src = src; buffIn.size = srcSize; buffIn.pos = 0; - ZSTD_compressStream(g_cstream, &buffOut, &buffIn); ZSTD_endStream(g_cstream, &buffOut); - return buffOut.pos; } @@ -385,13 +383,11 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) const BYTE* ip = dstBuff; const BYTE* iend; size_t frameHeaderSize, cBlockSize; - ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1); /* it would be better to use direct block compression here */ g_cSize = ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1); frameHeaderSize = ZSTD_getFrameHeader(&zfp, dstBuff, ZSTD_frameHeaderSize_min); if (frameHeaderSize==0) frameHeaderSize = ZSTD_frameHeaderSize_min; ip += frameHeaderSize; /* Skip frame Header */ - cBlockSize = ZSTD_getcBlockSize(ip, dstBuffSize, &bp); /* Get 1st block type */ if (bp.blockType != bt_compressed) { DISPLAY("ZSTD_decodeSeqHeaders : impossible to test on this sample (not compressible)\n"); @@ -399,7 +395,6 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) } iend = ip + ZSTD_blockHeaderSize + cBlockSize; /* End of first block */ ip += ZSTD_blockHeaderSize; /* skip block header */ - ZSTD_decompressBegin(g_zdc); ip += ZSTD_decodeLiteralsBlock(g_zdc, ip, iend-ip); /* skip literal segment */ g_cSize = iend-ip; diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 0281a406d..ce50925a1 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1655,9 +1655,9 @@ static int fuzzerTests_newAPI_opaque(U32 seed, U32 nbTests, unsigned startTest, } if (FUZ_rand(&lseed) & 1) CHECK_Z (ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_forceMaxWindow, FUZ_rand(&lseed) & 1) ); - +#if 0 if (FUZ_rand(&lseed) & 1) CHECK_Z (ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_test, FUZ_rand(&lseed) & 1) ); - +#endif /* Apply parameters */ From 91b30dbe847d8cad72b81de33e99dab650cb0f29 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Mon, 21 Aug 2017 10:09:06 -0700 Subject: [PATCH 015/248] Remove test parameter --- lib/common/zstd_internal.h | 40 ++++++------ lib/compress/zstd_compress.c | 108 ++++++++++++++------------------- lib/compress/zstdmt_compress.c | 12 ++-- lib/zstd.h | 26 +++++--- programs/fileio.c | 8 --- programs/fileio.h | 3 - programs/zstdcli.c | 3 - tests/Makefile | 2 +- tests/cctxParamRoundTrip.c | 25 ++++---- tests/zstreamtest.c | 7 --- 10 files changed, 98 insertions(+), 136 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 8b8419a4c..ee3164183 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -236,27 +236,6 @@ typedef struct { U32 repToConfirm[ZSTD_REP_NUM]; } seqStore_t; -struct ZSTD_CCtx_params_s { - ZSTD_compressionParameters cParams; - ZSTD_frameParameters fParams; - - int compressionLevel; - U32 forceWindow; /* force back-references to respect limit of 1<seqStore); } - -/* TODO: get rid of this function if possible*/ -static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( - ZSTD_compressionParameters cParams) -{ - ZSTD_CCtx_params cctxParams; - memset(&cctxParams, 0, sizeof(ZSTD_CCtx_params)); - cctxParams.cParams = cParams; - return cctxParams; -} - /* older variant; will be deprecated */ size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value) { @@ -239,7 +228,6 @@ size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned } } - #define ZSTD_CLEVEL_CUSTOM 999 static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx) { @@ -250,6 +238,16 @@ static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx) cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; } +static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( + ZSTD_compressionParameters cParams) +{ + ZSTD_CCtx_params cctxParams; + memset(&cctxParams, 0, sizeof(ZSTD_CCtx_params)); + cctxParams.cParams = cParams; + cctxParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; + return cctxParams; +} + ZSTD_CCtx_params* ZSTD_createCCtxParams(void) { ZSTD_CCtx_params* params = @@ -287,10 +285,8 @@ size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) static void ZSTD_cLevelToCCtxParams(ZSTD_CCtx_params* params) { if (params->compressionLevel == ZSTD_CLEVEL_CUSTOM) return; - // TODO: src size, code duplication params->cParams = ZSTD_getCParams(params->compressionLevel, 0, 0); params->compressionLevel = ZSTD_CLEVEL_CUSTOM; - } #define CLAMPCHECK(val,min,max) { \ @@ -305,7 +301,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v switch(param) { case ZSTD_p_compressionLevel: - if (value == 0) return 0; + if (value == 0) return 0; /* special value : 0 means "don't change anything" */ if (cctx->cdict) return ERROR(stage_wrong); return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); @@ -316,9 +312,9 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v case ZSTD_p_minMatch: case ZSTD_p_targetLength: case ZSTD_p_compressionStrategy: - if (value == 0) return 0; /* special value : 0 means "don't change anything" */ + if (value == 0) return 0; if (cctx->cdict) return ERROR(stage_wrong); - ZSTD_cLevelToCParams(cctx); + ZSTD_cLevelToCParams(cctx); /* Can optimize if srcSize is known */ return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); case ZSTD_p_contentSizeFlag: @@ -365,12 +361,6 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v if (cctx->requestedParams.nbThreads <= 1) return ERROR(parameter_unsupported); assert(cctx->mtctx != NULL); return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_overlapSectionLog, value); -#if 0 - case ZSTD_p_test : - DEBUGLOG(2, "Setting test parameter = %u", value); - cctx->requestedParams.testParam = (value > 0); - return 0; -#endif default: return ERROR(parameter_unsupported); } @@ -488,12 +478,6 @@ size_t ZSTD_CCtxParam_setParameter( if (params->nbThreads <= 1) { return ERROR(parameter_unsupported); } params->overlapSizeLog = value; return 0; -#if 0 - case ZSTD_p_test : - DEBUGLOG(2, "setting opaque: ZSTD_p_test: %u", value); - params->testParam = (value > 0); - return 0; -#endif default: return ERROR(parameter_unsupported); } @@ -525,10 +509,6 @@ static void ZSTD_debugPrintCCtxParams(ZSTD_CCtx_params* params) params->nbThreads, params->jobSize, params->overlapSizeLog); -#if 0 - DEBUGLOG(2, "testParam: %u", - params->testParam); -#endif } #endif @@ -537,6 +517,8 @@ static void ZSTD_debugPrintCCtxParams(ZSTD_CCtx_params* params) * Parameters are copied manually before the dictionary is loaded. * The multithreading parameters jobSize and overlapSizeLog are set only if * nbThreads >= 1. + * + * Pledged srcSize is treated as unknown. */ size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, ZSTD_CCtx_params* params) { @@ -564,10 +546,6 @@ size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, ZSTD_CCtx_params* params) cctx, ZSTD_p_overlapSizeLog, params->overlapSizeLog) ); } -#if 0 - /* Copy test parameter */ - cctx->requestedParams.testParam = params->testParam; -#endif return 0; } @@ -3748,7 +3726,6 @@ static ZSTD_CDict* ZSTD_createCDict_advanced_opaque( } } - ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference, ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams, ZSTD_customMem customMem) @@ -3791,32 +3768,36 @@ ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( size_t dictSize, ZSTD_CCtx_params* params) { - size_t const cctxSize = ZSTD_estimateCCtxSize_advanced_opaque(params); - size_t const neededSize = sizeof(ZSTD_CDict) + (params->dictContentByRef ? 0 : dictSize) - + cctxSize; - ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; - void* ptr; - DEBUGLOG(5, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7); - if ((size_t)workspace & 7) return NULL; /* 8-aligned */ - DEBUGLOG(5, "(workspaceSize < neededSize) : (%u < %u) => %u", - (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize)); - if (workspaceSize < neededSize) return NULL; + if (params == NULL) { return NULL; } + { ZSTD_CCtx_params cctxParams = *params; + size_t const cctxSize = ZSTD_estimateCCtxSize_advanced_opaque(params); + size_t const neededSize = sizeof(ZSTD_CDict) + + (cctxParams.dictContentByRef ? 0 : dictSize) + + cctxSize; + ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; + void* ptr; + DEBUGLOG(5, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7); + if ((size_t)workspace & 7) return NULL; /* 8-aligned */ + DEBUGLOG(5, "(workspaceSize < neededSize) : (%u < %u) => %u", + (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize)); + if (workspaceSize < neededSize) return NULL; - if (!params->dictContentByRef) { - memcpy(cdict+1, dict, dictSize); - dict = cdict+1; - ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize; - } else { - ptr = cdict+1; + if (!cctxParams.dictContentByRef) { + memcpy(cdict+1, dict, dictSize); + dict = cdict+1; + ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize; + } else { + ptr = cdict+1; + } + cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize); + cctxParams.dictContentByRef = 1; + + /* What if nbThreads > 1? */ + if (ZSTD_isError( ZSTD_initCDict_internal_opaque(cdict, dict, dictSize, cctxParams) )) + return NULL; + + return cdict; } - cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize); - params->dictContentByRef = 1; - - /* What if nbThreads > 1? */ - if (ZSTD_isError( ZSTD_initCDict_internal_opaque(cdict, dict, dictSize, *params) )) - return NULL; - - return cdict; } /*! ZSTD_initStaticCDict_advanced() : @@ -3861,8 +3842,7 @@ size_t ZSTD_compressBegin_usingCDict_advanced( ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) { if (cdict==NULL) return ERROR(dictionary_wrong); - { - ZSTD_CCtx_params params = cdict->refContext->appliedParams; + { ZSTD_CCtx_params params = cdict->refContext->appliedParams; params.fParams = fParams; params.dictMode = ZSTD_dm_auto; DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced"); diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 76a062f04..84f42220c 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -188,7 +188,8 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf) /** * TODO - * Resets parameters to zero for jobs? + * + * Sets parameters to zero for jobs. Notably, nbThreads should be zero? */ static void ZSTDMT_zeroCCtxParams(ZSTD_CCtx_params* params) { @@ -564,7 +565,6 @@ static size_t ZSTDMT_compress_advanced_opaque( DEBUGLOG(4, "nbChunks : %2u (chunkSize : %u bytes) ", nbChunks, (U32)avgChunkSize); if (nbChunks==1) { /* fallback to single-thread mode */ ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0]; - if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, cctxParams.fParams); return ZSTD_compress_advanced_opaque(cctx, dst, dstCapacity, src, srcSize, NULL, 0, requestedParams); } @@ -664,7 +664,6 @@ static size_t ZSTDMT_compress_advanced_opaque( if (!error) DEBUGLOG(4, "compressed size : %u ", (U32)dstPos); return error ? error : dstPos; } - } size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, @@ -750,6 +749,7 @@ size_t ZSTDMT_initCStream_internal_opaque( if (dict) { DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal); ZSTD_freeCDict(zcs->cdictLocal); + /* TODO: This will need a cctxParam version? */ zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0 /* byRef */, ZSTD_dm_auto, /* note : a loadPrefix becomes an internal CDict */ params.cParams, zcs->cMem); @@ -779,12 +779,10 @@ size_t ZSTDMT_initCStream_internal_opaque( zcs->allJobsCompleted = 0; if (params.fParams.checksumFlag) XXH64_reset(&zcs->xxhState, 0); return 0; - } -/** ZSTDMT_initCStream_internal() : - * internal usage only */ -size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, +/** ZSTDMT_initCStream_internal() */ +static size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, const void* dict, size_t dictSize, const ZSTD_CDict* cdict, ZSTD_parameters params, unsigned long long pledgedSrcSize) { diff --git a/lib/zstd.h b/lib/zstd.h index f02f28c82..bbecd5ea2 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -498,7 +498,7 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); * It will also consider src size to be arbitrarily "large", which is worst case. * If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced() can provide a tighter estimation. * ZSTD_estimateCCtxSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - * TODO: ZSTD_estimateCCtxSize_advanced_opaque() + * ZSTD_estimateCCtxSize_advanced_opaque() can be used in tandem with ZSTD_CCtxParam_setParameter(). * Note : CCtx estimation is only correct for single-threaded compression */ ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced(ZSTD_compressionParameters cParams); @@ -510,7 +510,7 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); * It will also consider src size to be arbitrarily "large", which is worst case. * If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced() can provide a tighter estimation. * ZSTD_estimateCStreamSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - * TODO: ZSTD_estimateCStreamSize_advanced_opaque() + * ZSTD_estimateCStreamSize_advanced_opaque() can be used in tandem with ZSTD_CCtxParam_setParameter(). * Note : CStream estimation is only correct for single-threaded compression. * ZSTD_DStream memory budget depends on window Size. * This information can be passed manually, using ZSTD_estimateDStreamSize, @@ -527,7 +527,7 @@ ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t sr /*! ZSTD_estimate?DictSize() : * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). * ZSTD_estimateCStreamSize_advanced() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced(). - * TODO: ZSTD_estimateCDictSize_advanced_opaque() + * ZSTD_estimateCDictSize_advanced_opaque() allows further compression parameters. ByReference can be set with ZSTD_CCtxParam_setParameter. * Note : dictionary created "byReference" are smaller */ ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference); @@ -613,7 +613,10 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( const void* dict, size_t dictSize, ZSTD_CCtx_params* params); +/* TODO */ ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); +/*! ZSTD_resetCCtxParams() : + * Reset params to default, with the default compression level. */ ZSTDLIB_API size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params); ZSTDLIB_API size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); @@ -1000,9 +1003,6 @@ typedef enum { /* advanced parameters - may not remain available after API update */ ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize, * even when referencing into Dictionary content (default:0) */ -#if 0 - ZSTD_p_test, -#endif } ZSTD_cParameter; @@ -1013,9 +1013,19 @@ typedef enum { * @result : 0, or an error code (which can be tested with ZSTD_isError()). */ ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value); -/* TODO */ +/*! ZSTD_CCtxParam_setParameter() : + * Similar to ZSTD_CCtx_setParameter. + * Set one compression parameter, selected by enum ZSTD_cParameter. + * Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_applyCCtxParams(). + * Note : when `value` is an enum, cast it to unsigned for proper type checking. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). */ ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value); -/* TODO */ + +/*! ZSTD_CCtx_applyCCtxParams() : + * Apply a set of ZSTD_CCtx_params to the compression context. + * This must be done before the dictionary is loaded. + * The pledgedSrcSize is treated as unknown. + * Multithreading parameters are applied only if nbThreads > 1. */ ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, ZSTD_CCtx_params* params); /*! ZSTD_CCtx_setPledgedSrcSize() : diff --git a/programs/fileio.c b/programs/fileio.c index 1fb249d6b..669052d8b 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -213,10 +213,6 @@ void FIO_setOverlapLog(unsigned overlapLog){ DISPLAYLEVEL(2, "Setting overlapLog is useless in single-thread mode \n"); g_overlapLog = overlapLog; } -#if 0 -static U32 g_testParamFlag = 0; -void FIO_setTestParamFlag(unsigned testParamFlag) { g_testParamFlag = testParamFlag; } -#endif /*-************************************* * Functions @@ -414,10 +410,6 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel, CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nbThreads, g_nbThreads) ); /* dictionary */ CHECK( ZSTD_CCtx_loadDictionary(ress.cctx, dictBuffer, dictBuffSize) ); -#if 0 - /* Test */ - CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_test, g_testParamFlag) ); -#endif } #elif defined(ZSTD_MULTITHREAD) { ZSTD_parameters params = ZSTD_getParams(cLevel, srcSize, dictBuffSize); diff --git a/programs/fileio.h b/programs/fileio.h index 497e122e1..9d9167df9 100644 --- a/programs/fileio.h +++ b/programs/fileio.h @@ -56,9 +56,6 @@ void FIO_setMemLimit(unsigned memLimit); void FIO_setNbThreads(unsigned nbThreads); void FIO_setBlockSize(unsigned blockSize); void FIO_setOverlapLog(unsigned overlapLog); -#if 0 -void FIO_setTestParamFlag(unsigned testParamFlag); -#endif /*-************************************* diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 5e95e4268..b1268c1f3 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -430,9 +430,6 @@ int main(int argCount, const char* argv[]) if (!strcmp(argument, "--keep")) { FIO_setRemoveSrcFile(0); continue; } if (!strcmp(argument, "--rm")) { FIO_setRemoveSrcFile(1); continue; } if (!strcmp(argument, "--priority=rt")) { setRealTimePrio = 1; continue; } -#if 0 - if (!strcmp(argument, "--testParam")) { FIO_setTestParamFlag(1); continue; } -#endif #ifdef ZSTD_GZCOMPRESS if (!strcmp(argument, "--format=gzip")) { suffix = GZ_EXTENSION; FIO_setCompressionType(FIO_gzipCompression); continue; } #endif diff --git a/tests/Makefile b/tests/Makefile index e815f5850..228f4cdd2 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -217,7 +217,7 @@ clean: fuzzer$(EXT) fuzzer32$(EXT) zbufftest$(EXT) zbufftest32$(EXT) \ fuzzer-dll$(EXT) zstreamtest-dll$(EXT) zbufftest-dll$(EXT)\ zstreamtest$(EXT) zstreamtest32$(EXT) \ - datagen$(EXT) paramgrill$(EXT) roundTripCrash$(EXT) longmatch$(EXT) \ + datagen$(EXT) paramgrill$(EXT) roundTripCrash$(EXT) cctxParamRoundTrip$(EXT) longmatch$(EXT) \ symbols$(EXT) invalidDictionaries$(EXT) legacy$(EXT) poolTests$(EXT) \ decodecorpus$(EXT) @echo Cleaning completed diff --git a/tests/cctxParamRoundTrip.c b/tests/cctxParamRoundTrip.c index 45a57a151..906ad9cec 100644 --- a/tests/cctxParamRoundTrip.c +++ b/tests/cctxParamRoundTrip.c @@ -32,6 +32,15 @@ *==========================================*/ #define MIN(a,b) ( (a) < (b) ? (a) : (b) ) +static void crash(int errorCode){ + /* abort if AFL/libfuzzer, exit otherwise */ + #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* could also use __AFL_COMPILER */ + abort(); + #else + exit(errorCode); + #endif +} + #define CHECK_Z(f) { \ size_t const err = f; \ if (ZSTD_isError(err)) { \ @@ -41,7 +50,6 @@ crash(1); \ } } - /** roundTripTest() : * Compresses `srcBuff` into `compressedBuff`, * then decompresses `compressedBuff` into `resultBuff`. @@ -61,10 +69,8 @@ static size_t roundTripTest(void* resultBuff, size_t resultBuffCapacity, ZSTD_inBuffer inBuffer = { srcBuff, srcBuffSize, 0 }; ZSTD_outBuffer outBuffer = {compressedBuff, compressedBuffCapacity, 0 }; - ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_compressionLevel, 1); - ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_test, 1); - - ZSTD_CCtx_applyCCtxParams(cctx, cctxParams); + CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_compressionLevel, 1) ); + CHECK_Z( ZSTD_CCtx_applyCCtxParams(cctx, cctxParams) ); CHECK_Z (ZSTD_compress_generic(cctx, &outBuffer, &inBuffer, ZSTD_e_end) ); @@ -88,15 +94,6 @@ static size_t checkBuffers(const void* buff1, const void* buff2, size_t buffSize return pos; } -static void crash(int errorCode){ - /* abort if AFL/libfuzzer, exit otherwise */ - #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* could also use __AFL_COMPILER */ - abort(); - #else - exit(errorCode); - #endif -} - static void roundTripCheck(const void* srcBuff, size_t srcBuffSize) { size_t const cBuffSize = ZSTD_compressBound(srcBuffSize); diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index ce50925a1..ced9c57ff 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1655,12 +1655,8 @@ static int fuzzerTests_newAPI_opaque(U32 seed, U32 nbTests, unsigned startTest, } if (FUZ_rand(&lseed) & 1) CHECK_Z (ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_forceMaxWindow, FUZ_rand(&lseed) & 1) ); -#if 0 - if (FUZ_rand(&lseed) & 1) CHECK_Z (ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_test, FUZ_rand(&lseed) & 1) ); -#endif /* Apply parameters */ - CHECK_Z (ZSTD_CCtx_applyCCtxParams(zc, cctxParams) ); if (FUZ_rand(&lseed) & 1) { @@ -1795,9 +1791,6 @@ _output_error: goto _cleanup; } - - - /*-******************************************************* * Command line *********************************************************/ From 502031ca10f07be4981f07cb6a7b87d8d1211806 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Mon, 21 Aug 2017 11:00:44 -0700 Subject: [PATCH 016/248] Use cctxParam version of createCDict internally --- lib/common/zstd_internal.h | 5 +++++ lib/compress/zstd_compress.c | 12 +++++++----- lib/compress/zstdmt_compress.c | 18 ++++++++---------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index ee3164183..65719f541 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -360,6 +360,11 @@ size_t ZSTD_initCStream_internal_opaque( ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); +/* INTERNAL */ +ZSTD_CDict* ZSTD_createCDict_advanced_opaque( + const void* dictBuffer, size_t dictSize, + ZSTD_CCtx_params params, ZSTD_customMem customMem); + /*! ZSTD_compressStream_generic() : * Private use only. To be called from zstdmt_compress.c in single-thread mode. */ size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index ee0365ca3..265be326f 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -3698,7 +3698,8 @@ static size_t ZSTD_initCDict_internal( } #endif -static ZSTD_CDict* ZSTD_createCDict_advanced_opaque( +/* Internal only */ +ZSTD_CDict* ZSTD_createCDict_advanced_opaque( const void* dictBuffer, size_t dictSize, ZSTD_CCtx_params params, ZSTD_customMem customMem) { @@ -3715,6 +3716,7 @@ static ZSTD_CDict* ZSTD_createCDict_advanced_opaque( } cdict->refContext = cctx; + /* TODO: What should be zero? */ if (ZSTD_isError( ZSTD_initCDict_internal_opaque( cdict, dictBuffer, dictSize, @@ -3992,10 +3994,10 @@ size_t ZSTD_initCStream_internal_opaque( return ERROR(memory_allocation); } ZSTD_freeCDict(zcs->cdictLocal); - zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, - params.dictContentByRef, - params.dictMode, - params.cParams, zcs->customMem); + /* TODO opaque version: what needs to be zero? */ + zcs->cdictLocal = ZSTD_createCDict_advanced_opaque( + dict, dictSize, + params, zcs->customMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); } else { diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 84f42220c..e7a05f4b1 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -195,6 +195,7 @@ static void ZSTDMT_zeroCCtxParams(ZSTD_CCtx_params* params) { params->forceWindow = 0; params->dictMode = (ZSTD_dictMode_e)(0); + params->dictContentByRef = 0; params->nbThreads = 0; params->jobSize = 0; params->overlapSizeLog = 0; @@ -719,13 +720,9 @@ size_t ZSTDMT_initCStream_internal_opaque( const ZSTD_CDict* cdict, ZSTD_CCtx_params cctxParams, unsigned long long pledgedSrcSize) { - ZSTD_parameters params; - params.cParams = cctxParams.cParams; - params.fParams = cctxParams.fParams; - DEBUGLOG(4, "ZSTDMT_initCStream_internal"); /* params are supposed to be fully validated at this point */ - assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + assert(!ZSTD_isError(ZSTD_checkCParams(cctxParams.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ /* TODO: Set stuff to 0 to preserve old semantics. */ @@ -749,10 +746,11 @@ size_t ZSTDMT_initCStream_internal_opaque( if (dict) { DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal); ZSTD_freeCDict(zcs->cdictLocal); - /* TODO: This will need a cctxParam version? */ - zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, - 0 /* byRef */, ZSTD_dm_auto, /* note : a loadPrefix becomes an internal CDict */ - params.cParams, zcs->cMem); + /* TODO: cctxParam version? Is this correct? + * by reference should be zero, mode should be ZSTD_dm_auto */ + zcs->cdictLocal = ZSTD_createCDict_advanced_opaque( + dict, dictSize, + cctxParams, zcs->cMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); } else { @@ -777,7 +775,7 @@ size_t ZSTDMT_initCStream_internal_opaque( zcs->nextJobID = 0; zcs->frameEnded = 0; zcs->allJobsCompleted = 0; - if (params.fParams.checksumFlag) XXH64_reset(&zcs->xxhState, 0); + if (cctxParams.fParams.checksumFlag) XXH64_reset(&zcs->xxhState, 0); return 0; } From f306d400c0d986dc246d74ea7916211c2bb45632 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Mon, 21 Aug 2017 11:12:11 -0700 Subject: [PATCH 017/248] [cover] Fix divide by zero --- lib/dictBuilder/cover.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index 3d445ae8b..cc4b13376 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -479,11 +479,16 @@ static COVER_segment_t COVER_selectSegment(const COVER_ctx_t *ctx, U32 *freqs, * Check the validity of the parameters. * Returns non-zero if the parameters are valid and 0 otherwise. */ -static int COVER_checkParameters(ZDICT_cover_params_t parameters) { +static int COVER_checkParameters(ZDICT_cover_params_t parameters, + size_t maxDictSize) { /* k and d are required parameters */ if (parameters.d == 0 || parameters.k == 0) { return 0; } + /* k <= maxDictSize */ + if (parameters.k > maxDictSize) { + return 0; + } /* d <= k */ if (parameters.d > parameters.k) { return 0; @@ -648,7 +653,7 @@ ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover( COVER_ctx_t ctx; COVER_map_t activeDmers; /* Checks */ - if (!COVER_checkParameters(parameters)) { + if (!COVER_checkParameters(parameters, dictBufferCapacity)) { DISPLAYLEVEL(1, "Cover parameters incorrect\n"); return ERROR(GENERIC); } @@ -995,7 +1000,7 @@ ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover( data->parameters.d = d; data->parameters.steps = kSteps; /* Check the parameters */ - if (!COVER_checkParameters(data->parameters)) { + if (!COVER_checkParameters(data->parameters, dictBufferCapacity)) { DISPLAYLEVEL(1, "Cover parameters incorrect\n"); free(data); continue; From 3587556873ff75ce4a5bed09d2d436ad3901c714 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Mon, 21 Aug 2017 11:16:47 -0700 Subject: [PATCH 018/248] [cover] Test small maxdict --- tests/playTests.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/playTests.sh b/tests/playTests.sh index bc8584e7a..706cef2da 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -291,8 +291,10 @@ $ECHO "- Create dictionary with wrong dictID parameter order (must fail)" $ZSTD --train *.c ../programs/*.c --dictID -o 1 tmpDict1 && die "wrong order : --dictID must be followed by argument " $ECHO "- Create dictionary with size limit" $ZSTD --train *.c ../programs/*.c -o tmpDict2 --maxdict=4K -v +$ECHO "- Create dictionary with small size limit" +$ZSTD --train *.c ../programs/*.c -o tmpDict3 --maxdict=1K -v $ECHO "- Create dictionary with wrong parameter order (must fail)" -$ZSTD --train *.c ../programs/*.c -o tmpDict2 --maxdict -v 4K && die "wrong order : --maxdict must be followed by argument " +$ZSTD --train *.c ../programs/*.c -o tmpDict3 --maxdict -v 4K && die "wrong order : --maxdict must be followed by argument " $ECHO "- Compress without dictID" $ZSTD -f tmp -D tmpDict1 --no-dictID $ZSTD -d tmp.zst -D tmpDict -fo result From 232d62b6371e18678300e5569f507f3eb8f29ee8 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 21 Aug 2017 11:24:32 -0700 Subject: [PATCH 019/248] fixed a few headers that were too hastily copy/pasted during last license change --- examples/dictionary_compression.c | 9 ++++----- examples/dictionary_decompression.c | 9 ++++----- examples/multiple_streaming_compression.c | 9 ++++----- examples/simple_compression.c | 9 ++++----- examples/simple_decompression.c | 9 ++++----- examples/streaming_compression.c | 9 ++++----- examples/streaming_decompression.c | 9 ++++----- lib/compress/zstd_opt.h | 2 +- programs/platform.h | 2 +- programs/util.h | 2 +- zlibWrapper/examples/zwrapbench.c | 3 +-- zlibWrapper/gzcompatibility.h | 2 +- zlibWrapper/zstd_zlibwrapper.c | 2 +- zlibWrapper/zstd_zlibwrapper.h | 2 +- 14 files changed, 35 insertions(+), 43 deletions(-) diff --git a/examples/dictionary_compression.c b/examples/dictionary_compression.c index 17acec98d..adcc3b4d5 100644 --- a/examples/dictionary_compression.c +++ b/examples/dictionary_compression.c @@ -1,10 +1,9 @@ -/* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +/** + * Copyright 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). + * This source code is licensed under the license found in the + * LICENSE-examples file in the root directory of this source tree. */ diff --git a/examples/dictionary_decompression.c b/examples/dictionary_decompression.c index 345c968c3..ef739c189 100644 --- a/examples/dictionary_decompression.c +++ b/examples/dictionary_decompression.c @@ -1,10 +1,9 @@ -/* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +/** + * Copyright 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). + * This source code is licensed under the license found in the + * LICENSE-examples file in the root directory of this source tree. */ diff --git a/examples/multiple_streaming_compression.c b/examples/multiple_streaming_compression.c index 7bfa133ee..61699104c 100644 --- a/examples/multiple_streaming_compression.c +++ b/examples/multiple_streaming_compression.c @@ -1,10 +1,9 @@ -/* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +/** + * Copyright 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). + * This source code is licensed under the license found in the + * LICENSE-examples file in the root directory of this source tree. */ diff --git a/examples/simple_compression.c b/examples/simple_compression.c index 95853faa6..ab1131475 100644 --- a/examples/simple_compression.c +++ b/examples/simple_compression.c @@ -1,10 +1,9 @@ -/* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +/** + * Copyright 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). + * This source code is licensed under the license found in the + * LICENSE-examples file in the root directory of this source tree. */ diff --git a/examples/simple_decompression.c b/examples/simple_decompression.c index 9e9fcc9ed..4b7ea59e5 100644 --- a/examples/simple_decompression.c +++ b/examples/simple_decompression.c @@ -1,10 +1,9 @@ -/* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +/** + * Copyright 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). + * This source code is licensed under the license found in the + * LICENSE-examples file in the root directory of this source tree. */ #include // malloc, exit diff --git a/examples/streaming_compression.c b/examples/streaming_compression.c index ac7ee7687..24ad15bd6 100644 --- a/examples/streaming_compression.c +++ b/examples/streaming_compression.c @@ -1,10 +1,9 @@ -/* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +/** + * Copyright 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). + * This source code is licensed under the license found in the + * LICENSE-examples file in the root directory of this source tree. */ diff --git a/examples/streaming_decompression.c b/examples/streaming_decompression.c index 76dd85169..bb2d80987 100644 --- a/examples/streaming_decompression.c +++ b/examples/streaming_decompression.c @@ -1,10 +1,9 @@ -/* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +/** + * Copyright 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). + * This source code is licensed under the license found in the + * LICENSE-examples file in the root directory of this source tree. */ diff --git a/lib/compress/zstd_opt.h b/lib/compress/zstd_opt.h index ae24732c7..4d938c80d 100644 --- a/lib/compress/zstd_opt.h +++ b/lib/compress/zstd_opt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/programs/platform.h b/programs/platform.h index fb2e9b173..e9629a0fa 100644 --- a/programs/platform.h +++ b/programs/platform.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/programs/util.h b/programs/util.h index 7b553661c..d6e1dfc20 100644 --- a/programs/util.h +++ b/programs/util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index 050c9db63..82ec47b70 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -36,7 +36,6 @@ #endif - /*-************************************ * Constants **************************************/ diff --git a/zlibWrapper/gzcompatibility.h b/zlibWrapper/gzcompatibility.h index ac9020acc..98ddf1f11 100644 --- a/zlibWrapper/gzcompatibility.h +++ b/zlibWrapper/gzcompatibility.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 272369a28..836587f2b 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/zlibWrapper/zstd_zlibwrapper.h b/zlibWrapper/zstd_zlibwrapper.h index f8f368009..9c923cb18 100644 --- a/zlibWrapper/zstd_zlibwrapper.h +++ b/zlibWrapper/zstd_zlibwrapper.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the From 25be09c6b47dc4cff63bfe447a1b3499e00d66e6 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Mon, 21 Aug 2017 11:34:53 -0700 Subject: [PATCH 020/248] Set some parameters to zero before initializing cdict --- lib/compress/zstd_compress.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 265be326f..530611dd5 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -3708,15 +3708,12 @@ ZSTD_CDict* ZSTD_createCDict_advanced_opaque( { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem); - if (!cdict || !cctx) { ZSTD_free(cdict, customMem); ZSTD_freeCCtx(cctx); return NULL; } cdict->refContext = cctx; - - /* TODO: What should be zero? */ if (ZSTD_isError( ZSTD_initCDict_internal_opaque( cdict, dictBuffer, dictSize, @@ -4256,7 +4253,7 @@ size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuf return ZSTD_compressStream_generic(zcs, output, input, ZSTD_e_continue); } -/*! ZSTDMT_initCStream_internal() : +/*! ZSTDMT_initCStream_internal_opaque() : * Private use only. Init streaming operation. * expects params to be valid. * must receive dict, or cdict, or none, but not both. From 560b34f6d2c305fc91cf08838c807f13497a261c Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Mon, 21 Aug 2017 11:44:58 -0700 Subject: [PATCH 021/248] Return error code when initializing NULL cctxParams --- lib/compress/zstd_compress.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 530611dd5..69e977890 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -268,6 +268,7 @@ size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params) size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) { + if (!cctxParams) { return ERROR(GENERIC); } memset(cctxParams, 0, sizeof(ZSTD_CCtx_params)); cctxParams->cParams = params.cParams; cctxParams->fParams = params.fParams; From 73c73bf16a0e9aafe0776144469b1bbf9f26b193 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Mon, 21 Aug 2017 12:41:19 -0700 Subject: [PATCH 022/248] Reduce code duplication in zstreamtest --- lib/zstd.h | 2 +- tests/zstreamtest.c | 73 +++++++++++++++++++++++++++++---------------- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/lib/zstd.h b/lib/zstd.h index bbecd5ea2..a88382e5c 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -1002,7 +1002,7 @@ typedef enum { /* advanced parameters - may not remain available after API update */ ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize, - * even when referencing into Dictionary content (default:0) */ + * even when referencing into Dictionary content (default:0) */ } ZSTD_cParameter; diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index ced9c57ff..8f974b461 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1206,6 +1206,7 @@ _output_error: /* Tests for ZSTD_compress_generic() API */ +#if 0 static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests) { U32 const maxSrcLog = bigTests ? 24 : 22; @@ -1493,8 +1494,22 @@ _output_error: result = 1; goto _cleanup; } +#endif -static int fuzzerTests_newAPI_opaque(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests) +/** If useOpaqueAPI, sets param in cctxParams. + * Otherwise, sets the param in zc. */ +static size_t setCCtxParameter(ZSTD_CCtx* zc, ZSTD_CCtx_params* cctxParams, + ZSTD_cParameter param, unsigned value, + U32 useOpaqueAPI) +{ + if (useOpaqueAPI) { + return ZSTD_CCtxParam_setParameter(cctxParams, param, value); + } else { + return ZSTD_CCtx_setParameter(zc, param, value); + } +} + +static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests, U32 const useOpaqueAPI) { U32 const maxSrcLog = bigTests ? 24 : 22; static const U32 maxSampleLog = 19; @@ -1597,7 +1612,7 @@ static int fuzzerTests_newAPI_opaque(U32 seed, U32 nbTests, unsigned startTest, maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2); if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1; { int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1; - CHECK_Z (ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_compressionLevel, compressionLevel)); + CHECK_Z (setCCtxParameter(zc, cctxParams, ZSTD_p_compressionLevel, compressionLevel, useOpaqueAPI) ); } } else { U32 const testLog = FUZ_rand(&lseed) % maxSrcLog; @@ -1627,45 +1642,53 @@ static int fuzzerTests_newAPI_opaque(U32 seed, U32 nbTests, unsigned startTest, cParams.targetLength = (U32)(cParams.targetLength * (0.5 + ((double)(FUZ_rand(&lseed) & 127) / 128))); cParams = ZSTD_adjustCParams(cParams, 0, 0); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_windowLog, cParams.windowLog) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_hashLog, cParams.hashLog) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_chainLog, cParams.chainLog) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_searchLog, cParams.searchLog) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_minMatch, cParams.searchLength) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_targetLength, cParams.targetLength) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_windowLog, cParams.windowLog, useOpaqueAPI) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_hashLog, cParams.hashLog, useOpaqueAPI) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_chainLog, cParams.chainLog, useOpaqueAPI) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_searchLog, cParams.searchLog, useOpaqueAPI) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_minMatch, cParams.searchLength, useOpaqueAPI) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_targetLength, cParams.targetLength, useOpaqueAPI) ); /* unconditionally set, to be sync with decoder */ /* mess with frame parameters */ - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_checksumFlag, FUZ_rand(&lseed) & 1) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_dictIDFlag, FUZ_rand(&lseed) & 1) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_contentSizeFlag, FUZ_rand(&lseed) & 1) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_checksumFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_dictIDFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_contentSizeFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) ); DISPLAYLEVEL(5, "pledgedSrcSize : %u \n", (U32)pledgedSrcSize); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_refDictContent, FUZ_rand(&lseed) & 1) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_refDictContent, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); /* multi-threading parameters */ { U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1; U32 const nbThreads = MIN(nbThreadsCandidate, nbThreadsMax); - CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_nbThreads, nbThreads) ); + CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_nbThreads, nbThreads, useOpaqueAPI) ); if (nbThreads > 1) { U32 const jobLog = FUZ_rand(&lseed) % (testLog+1); - CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_overlapSizeLog, FUZ_rand(&lseed) % 10) ); - CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_jobSize, (U32)FUZ_rLogLength(&lseed, jobLog)) ); + CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_overlapSizeLog, FUZ_rand(&lseed) % 10, useOpaqueAPI) ); + CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_jobSize, (U32)FUZ_rLogLength(&lseed, jobLog), useOpaqueAPI) ); } } - if (FUZ_rand(&lseed) & 1) CHECK_Z (ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_forceMaxWindow, FUZ_rand(&lseed) & 1) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z (setCCtxParameter(zc, cctxParams, ZSTD_p_forceMaxWindow, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); /* Apply parameters */ - CHECK_Z (ZSTD_CCtx_applyCCtxParams(zc, cctxParams) ); + if (useOpaqueAPI) { + CHECK_Z (ZSTD_CCtx_applyCCtxParams(zc, cctxParams) ); + } if (FUZ_rand(&lseed) & 1) { CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) ); if (dict && dictSize) { /* test that compression parameters are rejected (correctly) after loading a non-NULL dictionary */ - size_t const setError = ZSTD_CCtx_applyCCtxParams(zc, cctxParams); - CHECK(!ZSTD_isError(setError), "ZSTD_CCtx_applyCCtxParams should have failed"); - } } else { + if (useOpaqueAPI) { + size_t const setError = ZSTD_CCtx_applyCCtxParams(zc, cctxParams); + CHECK(!ZSTD_isError(setError), "ZSTD_CCtx_applyCCtxParams should have failed"); + } else { + size_t const setError = ZSTD_CCtx_setParameter(zc, ZSTD_p_windowLog, cParams.windowLog-1); + CHECK(!ZSTD_isError(setError), "ZSTD_CCtx_setParameter should have failed"); + } + } + } else { CHECK_Z( ZSTD_CCtx_refPrefix(zc, dict, dictSize) ); } } } @@ -1810,7 +1833,7 @@ int FUZ_usage(const char* programName) return 0; } -typedef enum { simple_api, mt_api, advanced_api, advanced_api_opaque } e_api; +typedef enum { simple_api, mt_api, advanced_api } e_api; int main(int argc, const char** argv) { @@ -1826,6 +1849,7 @@ int main(int argc, const char** argv) e_api selected_api = simple_api; const char* const programName = argv[0]; ZSTD_customMem const customNULL = ZSTD_defaultCMem; + U32 useOpaqueAPI = 0; /* Check command line */ for(argNb=1; argNb Date: Mon, 21 Aug 2017 12:57:18 -0700 Subject: [PATCH 023/248] Pass ZSTD_CCtx_params as const ptr when possible --- lib/compress/zstd_compress.c | 18 +++++++++--------- lib/zstd.h | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 69e977890..b6774e947 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -521,7 +521,7 @@ static void ZSTD_debugPrintCCtxParams(ZSTD_CCtx_params* params) * * Pledged srcSize is treated as unknown. */ -size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, ZSTD_CCtx_params* params) +size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) { if (params == NULL) { return ERROR(GENERIC); } if (cctx->cdict) { return ERROR(stage_wrong); } @@ -693,10 +693,10 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); } -size_t ZSTD_estimateCCtxSize_advanced_opaque(ZSTD_CCtx_params* params) +size_t ZSTD_estimateCCtxSize_advanced_opaque(const ZSTD_CCtx_params* params) { if (params == NULL) { return 0; } - { ZSTD_compressionParameters cParams = params->cParams; + { ZSTD_compressionParameters const cParams = params->cParams; size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); U32 const divider = (cParams.searchLength==3) ? 3 : 4; @@ -725,7 +725,7 @@ size_t ZSTD_estimateCCtxSize_advanced_opaque(ZSTD_CCtx_params* params) size_t ZSTD_estimateCCtxSize_advanced(ZSTD_compressionParameters cParams) { - ZSTD_CCtx_params params = ZSTD_makeCCtxParamsFromCParams(cParams); + ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); return ZSTD_estimateCCtxSize_advanced_opaque(¶ms); } @@ -735,7 +735,7 @@ size_t ZSTD_estimateCCtxSize(int compressionLevel) return ZSTD_estimateCCtxSize_advanced(cParams); } -size_t ZSTD_estimateCStreamSize_advanced_opaque(ZSTD_CCtx_params* params) +size_t ZSTD_estimateCStreamSize_advanced_opaque(const ZSTD_CCtx_params* params) { if (params == NULL) { return 0; } { size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced_opaque(params); @@ -750,7 +750,7 @@ size_t ZSTD_estimateCStreamSize_advanced_opaque(ZSTD_CCtx_params* params) size_t ZSTD_estimateCStreamSize_advanced(ZSTD_compressionParameters cParams) { - ZSTD_CCtx_params params = ZSTD_makeCCtxParamsFromCParams(cParams); + ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); return ZSTD_estimateCStreamSize_advanced_opaque(¶ms); } @@ -3608,7 +3608,7 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcS /* ===== Dictionary API ===== */ size_t ZSTD_estimateCDictSize_advanced_opaque( - size_t dictSize, ZSTD_CCtx_params* params) + size_t dictSize, const ZSTD_CCtx_params* params) { if (params == NULL) { return 0; } DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict)); @@ -3766,7 +3766,7 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict) ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( void *workspace, size_t workspaceSize, const void* dict, size_t dictSize, - ZSTD_CCtx_params* params) + const ZSTD_CCtx_params* params) { if (params == NULL) { return NULL; } { ZSTD_CCtx_params cctxParams = *params; @@ -3928,7 +3928,7 @@ static size_t ZSTD_resetCStream_internal_opaque( ZSTD_CStream* zcs, const void* dict, size_t dictSize, const ZSTD_CDict* cdict, - ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) + const ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) { DEBUGLOG(4, "ZSTD_resetCStream_internal"); /* params are supposed to be fully validated at this point */ diff --git a/lib/zstd.h b/lib/zstd.h index a88382e5c..0fd97cd6f 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -502,7 +502,7 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); * Note : CCtx estimation is only correct for single-threaded compression */ ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced(ZSTD_compressionParameters cParams); -ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced_opaque(ZSTD_CCtx_params* params); +ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced_opaque(const ZSTD_CCtx_params* params); ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); /*! ZSTD_estimate?StreamSize() : @@ -520,7 +520,7 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); * In this case, get total size by adding ZSTD_estimate?DictSize */ ZSTDLIB_API size_t ZSTD_estimateCStreamSize(int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced(ZSTD_compressionParameters cParams); -ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced_opaque(ZSTD_CCtx_params* params); +ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced_opaque(const ZSTD_CCtx_params* params); ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize); ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); @@ -531,7 +531,7 @@ ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t sr * Note : dictionary created "byReference" are smaller */ ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference); -ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced_opaque(size_t dictSize, ZSTD_CCtx_params* params); +ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced_opaque(size_t dictSize, const ZSTD_CCtx_params* params); ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference); @@ -611,7 +611,7 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict( ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( void* workspace, size_t workspaceSize, const void* dict, size_t dictSize, - ZSTD_CCtx_params* params); + const ZSTD_CCtx_params* params); /* TODO */ ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); @@ -1026,7 +1026,7 @@ ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cP * This must be done before the dictionary is loaded. * The pledgedSrcSize is treated as unknown. * Multithreading parameters are applied only if nbThreads > 1. */ -ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, ZSTD_CCtx_params* params); +ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); /*! ZSTD_CCtx_setPledgedSrcSize() : * Total input data size to be compressed as a single frame. From d49eb40c03845d0961f2819f502c51a11bd7cbe5 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Mon, 21 Aug 2017 13:10:03 -0700 Subject: [PATCH 024/248] [cover] Stop when segmentSize is less than d --- lib/dictBuilder/cover.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index 3d445ae8b..501b5b490 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -622,9 +622,9 @@ static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs, /* Select a segment */ COVER_segment_t segment = COVER_selectSegment( ctx, freqs, activeDmers, epochBegin, epochEnd, parameters); - /* Trim the segment if necessary and if it is empty then we are done */ + /* Trim the segment if necessary and if it is too small then we are done */ segmentSize = MIN(segment.end - segment.begin + parameters.d - 1, tail); - if (segmentSize == 0) { + if (segmentSize < parameters.d) { break; } /* We fill the dictionary from the back to allow the best segments to be From 1c0dbe81b17addc1f48be895326124158ea5a2c3 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Mon, 21 Aug 2017 13:18:00 -0700 Subject: [PATCH 025/248] Add documentation for CCtx_params --- lib/compress/zstd_compress.c | 8 +++-- lib/zstd.h | 60 +++++++++++++++++++++++------------- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index b6774e947..c37b2ad49 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -471,12 +471,12 @@ size_t ZSTD_CCtxParam_setParameter( return 0; case ZSTD_p_jobSize : - if (params->nbThreads <= 1) { return ERROR(parameter_unsupported); } + if (params->nbThreads <= 1) return ERROR(parameter_unsupported); params->jobSize = value; return 0; case ZSTD_p_overlapSizeLog : - if (params->nbThreads <= 1) { return ERROR(parameter_unsupported); } + if (params->nbThreads <= 1) return ERROR(parameter_unsupported); params->overlapSizeLog = value; return 0; @@ -526,6 +526,10 @@ size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params if (params == NULL) { return ERROR(GENERIC); } if (cctx->cdict) { return ERROR(stage_wrong); } + /* TODO: some parameters can be set even if cctx->cdict. + * They can be set directly using ZSTD_CCtx_setParameter? + */ + /* Assume the compression and frame parameters are validated */ cctx->requestedParams.cParams = params->cParams; cctx->requestedParams.fParams = params->fParams; diff --git a/lib/zstd.h b/lib/zstd.h index 0fd97cd6f..09b89911f 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -613,13 +613,7 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( const void* dict, size_t dictSize, const ZSTD_CCtx_params* params); -/* TODO */ -ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); -/*! ZSTD_resetCCtxParams() : - * Reset params to default, with the default compression level. */ -ZSTDLIB_API size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params); -ZSTDLIB_API size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); -ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); + /*! ZSTD_getCParams() : * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. @@ -1013,21 +1007,6 @@ typedef enum { * @result : 0, or an error code (which can be tested with ZSTD_isError()). */ ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value); -/*! ZSTD_CCtxParam_setParameter() : - * Similar to ZSTD_CCtx_setParameter. - * Set one compression parameter, selected by enum ZSTD_cParameter. - * Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_applyCCtxParams(). - * Note : when `value` is an enum, cast it to unsigned for proper type checking. - * @result : 0, or an error code (which can be tested with ZSTD_isError()). */ -ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value); - -/*! ZSTD_CCtx_applyCCtxParams() : - * Apply a set of ZSTD_CCtx_params to the compression context. - * This must be done before the dictionary is loaded. - * The pledgedSrcSize is treated as unknown. - * Multithreading parameters are applied only if nbThreads > 1. */ -ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); - /*! ZSTD_CCtx_setPledgedSrcSize() : * Total input data size to be compressed as a single frame. * This value will be controlled at the end, and result in error if not respected. @@ -1131,7 +1110,44 @@ size_t ZSTD_compress_generic_simpleArgs ( const void* src, size_t srcSize, size_t* srcPos, ZSTD_EndDirective endOp); +/** ZSTD_CCtx_params : + * + * - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure + * - ZSTD_CCtxParam_setParameter() : Push parameters one by one into an + * existing ZSTD_CCtx_params structure. This is similar to + * ZSTD_CCtx_setParameter(). + * - ZSTD_CCtx_applyCCtxParams() : Apply parameters to an existing CCtx. These + * parameters will be applied to all subsequent compression jobs. + * - ZSTD_compress_generic() : Do compression using the CCtx. + * - ZSTD_freeCCtxParams() : Free the memory. */ +ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); + +/*! ZSTD_resetCCtxParams() : + * Reset params to default, with the default compression level. */ +ZSTDLIB_API size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params); + +/*! ZSTD_initCCtxParams() : + * Set the compression and frame parameters of cctxParams according to params. + * All other parameters are reset to their default values. */ +ZSTDLIB_API size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); + +ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); + +/*! ZSTD_CCtxParam_setParameter() : + * Similar to ZSTD_CCtx_setParameter. + * Set one compression parameter, selected by enum ZSTD_cParameter. + * Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_applyCCtxParams(). + * Note : when `value` is an enum, cast it to unsigned for proper type checking. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). */ +ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value); + +/*! ZSTD_CCtx_applyCCtxParams() : + * Apply a set of ZSTD_CCtx_params to the compression context. + * This must be done before the dictionary is loaded. + * The pledgedSrcSize is treated as unknown. + * Multithreading parameters are applied only if nbThreads > 1. */ +ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); /** Block functions From fd8a25786efe8f6696e8c964dc8b6f247c759203 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Mon, 21 Aug 2017 13:23:35 -0700 Subject: [PATCH 026/248] Check parameters are valid in initCCtxParams --- lib/compress/zstd_compress.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index c37b2ad49..a85683059 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -266,9 +266,10 @@ size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params) return 0; } -size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) +size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, ZSTD_parameters const params) { if (!cctxParams) { return ERROR(GENERIC); } + CHECK_F( ZSTD_checkCParams(params.cParams) ); memset(cctxParams, 0, sizeof(ZSTD_CCtx_params)); cctxParams->cParams = params.cParams; cctxParams->fParams = params.fParams; From 9a54a315aa28a6659b935bd6ce95cb962715ebbc Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Mon, 21 Aug 2017 13:30:07 -0700 Subject: [PATCH 027/248] [cover] Convert score to U32 and check for zero --- lib/dictBuilder/cover.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index 501b5b490..07fedc2d1 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -382,7 +382,7 @@ static void COVER_group(COVER_ctx_t *ctx, const void *group, typedef struct { U32 begin; U32 end; - double score; + U32 score; } COVER_segment_t; /** @@ -622,6 +622,10 @@ static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs, /* Select a segment */ COVER_segment_t segment = COVER_selectSegment( ctx, freqs, activeDmers, epochBegin, epochEnd, parameters); + /* If the segment covers no dmers, then we are out of content */ + if (segment.score == 0) { + break; + } /* Trim the segment if necessary and if it is too small then we are done */ segmentSize = MIN(segment.end - segment.begin + parameters.d - 1, tail); if (segmentSize < parameters.d) { From 98de3f6847052019bb0a35a50f294d0d87a137ad Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Mon, 21 Aug 2017 14:23:17 -0700 Subject: [PATCH 028/248] [cover] Add dictionary size to compressed size --- lib/dictBuilder/cover.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index 07fedc2d1..3770c2cac 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -888,7 +888,7 @@ static void COVER_tryParameters(void *opaque) { goto _compressCleanup; } /* Compress each sample and sum their sizes (or error) */ - totalCompressedSize = 0; + totalCompressedSize = dictBufferCapacity; for (i = 0; i < ctx->nbSamples; ++i) { const size_t size = ZSTD_compress_usingCDict( cctx, dst, dstCapacity, ctx->samples + ctx->offsets[i], From 29c2d9a4d05213adac3bdb8b5855d80079112799 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Mon, 21 Aug 2017 14:28:31 -0700 Subject: [PATCH 029/248] [cover] Turn down notification for ZDICT subroutines --- lib/dictBuilder/cover.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index 3770c2cac..64f23f23c 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -998,6 +998,7 @@ ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover( data->parameters.k = k; data->parameters.d = d; data->parameters.steps = kSteps; + data->parameters.zParams.notificationLevel = g_displayLevel; /* Check the parameters */ if (!COVER_checkParameters(data->parameters)) { DISPLAYLEVEL(1, "Cover parameters incorrect\n"); From 5b956f4753c87905e8ae69ae3458e5ef56e44f07 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Mon, 21 Aug 2017 14:49:16 -0700 Subject: [PATCH 030/248] Comment out CCtx_param versions of CDict functions --- lib/common/zstd_internal.h | 5 -- lib/compress/zstd_compress.c | 119 +++++++++++++++++++++++++-------- lib/compress/zstdmt_compress.c | 9 ++- lib/zstd.h | 9 --- 4 files changed, 96 insertions(+), 46 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 65719f541..ee3164183 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -360,11 +360,6 @@ size_t ZSTD_initCStream_internal_opaque( ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); -/* INTERNAL */ -ZSTD_CDict* ZSTD_createCDict_advanced_opaque( - const void* dictBuffer, size_t dictSize, - ZSTD_CCtx_params params, ZSTD_customMem customMem); - /*! ZSTD_compressStream_generic() : * Private use only. To be called from zstdmt_compress.c in single-thread mode. */ size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index a85683059..649cf8780 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -3611,7 +3611,7 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcS /* ===== Dictionary API ===== */ - +#if 0 size_t ZSTD_estimateCDictSize_advanced_opaque( size_t dictSize, const ZSTD_CCtx_params* params) { @@ -3623,14 +3623,17 @@ size_t ZSTD_estimateCDictSize_advanced_opaque( + (params->dictContentByRef ? 0 : dictSize); } +#endif /*! ZSTD_estimateCDictSize_advanced() : * Estimate amount of memory that will be needed to create a dictionary with following arguments */ size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference) { - ZSTD_CCtx_params params = ZSTD_makeCCtxParamsFromCParams(cParams); - params.dictContentByRef = byReference; - return ZSTD_estimateCDictSize_advanced_opaque(dictSize, ¶ms); + DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict)); + DEBUGLOG(5, "CCtx estimate : %u", + (U32)ZSTD_estimateCCtxSize_advanced(cParams)); + return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced(cParams) + + (byReference ? 0 : dictSize); } size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) @@ -3657,6 +3660,7 @@ static ZSTD_parameters ZSTD_makeParams(ZSTD_compressionParameters cParams, ZSTD_ } #endif +#if 0 static size_t ZSTD_initCDict_internal_opaque(ZSTD_CDict* cdict, const void* dictBuffer, size_t dictSize, ZSTD_CCtx_params params) @@ -3683,27 +3687,44 @@ static size_t ZSTD_initCDict_internal_opaque(ZSTD_CDict* cdict, ZSTDb_not_buffered) ); return 0; } +#endif -#if 0 static size_t ZSTD_initCDict_internal( ZSTD_CDict* cdict, const void* dictBuffer, size_t dictSize, unsigned byReference, ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams) { - ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams; - ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, + DEBUGLOG(5, "ZSTD_initCDict_internal, mode %u", (U32)dictMode); + if ((byReference) || (!dictBuffer) || (!dictSize)) { + cdict->dictBuffer = NULL; + cdict->dictContent = dictBuffer; + } else { + void* const internalBuffer = ZSTD_malloc(dictSize, cdict->refContext->customMem); + cdict->dictBuffer = internalBuffer; + cdict->dictContent = internalBuffer; + if (!internalBuffer) return ERROR(memory_allocation); + memcpy(internalBuffer, dictBuffer, dictSize); + } + cdict->dictContentSize = dictSize; + + { ZSTD_frameParameters const fParams = { 0 /*contentSizeFlag */, 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */ - cctxParams.cParams = cParams; - cctxParams.fParams = fParams; - cctxParams.dictMode = dictMode; - cctxParams.dictContentByRef = byReference; - CHECK_F (ZSTD_initCDict_internal_opaque( - cdict, dictBuffer, dictSize, cctxParams) ); + ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams; + cctxParams.fParams = fParams; + cctxParams.cParams = cParams; + cctxParams.dictContentByRef = byReference; + cctxParams.dictMode = dictMode; + CHECK_F( ZSTD_compressBegin_internal(cdict->refContext, + cdict->dictContent, dictSize, + NULL, + cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, + ZSTDb_not_buffered) ); + } return 0; } -#endif +#if 0 /* Internal only */ ZSTD_CDict* ZSTD_createCDict_advanced_opaque( const void* dictBuffer, size_t dictSize, @@ -3730,15 +3751,33 @@ ZSTD_CDict* ZSTD_createCDict_advanced_opaque( return cdict; } } +#endif ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference, ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams, ZSTD_customMem customMem) { - ZSTD_CCtx_params cctxParams = ZSTD_makeCCtxParamsFromCParams(cParams); - cctxParams.dictMode = dictMode; - cctxParams.dictContentByRef = byReference; - return ZSTD_createCDict_advanced_opaque(dictBuffer, dictSize, cctxParams, customMem); + DEBUGLOG(5, "ZSTD_createCDict_advanced, mode %u", dictMode); + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; + + { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); + ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem); + if (!cdict || !cctx) { + ZSTD_free(cdict, customMem); + ZSTD_freeCCtx(cctx); + return NULL; + } + cdict->refContext = cctx; + if (ZSTD_isError( ZSTD_initCDict_internal( + cdict, + dictBuffer, dictSize, + byReference, dictMode, + cParams) )) { + ZSTD_freeCDict(cdict); + return NULL; + } + return cdict; + } } ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) @@ -3768,6 +3807,7 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict) } } +#if 0 ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( void *workspace, size_t workspaceSize, const void* dict, size_t dictSize, @@ -3804,6 +3844,7 @@ ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( return cdict; } } +#endif /*! ZSTD_initStaticCDict_advanced() : * Generate a digested dictionary in provided memory area. @@ -3823,13 +3864,35 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, unsigned byReference, ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams) { - ZSTD_CCtx_params params = ZSTD_makeCCtxParamsFromCParams(cParams); - params.dictMode = dictMode; - params.dictContentByRef = byReference; - return ZSTD_initStaticCDict_advanced_opaque( - workspace, workspaceSize, dict, dictSize, - ¶ms); + size_t const cctxSize = ZSTD_estimateCCtxSize_advanced(cParams); + size_t const neededSize = sizeof(ZSTD_CDict) + + (byReference ? 0 : dictSize) + + cctxSize; + ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; + void* ptr; + DEBUGLOG(5, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7); + if ((size_t)workspace & 7) return NULL; /* 8-aligned */ + DEBUGLOG(5, "(workspaceSize < neededSize) : (%u < %u) => %u", + (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize)); + if (workspaceSize < neededSize) return NULL; + + if (!byReference) { + memcpy(cdict+1, dict, dictSize); + dict = cdict+1; + ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize; + } else { + ptr = cdict+1; + } + cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize); + + if (ZSTD_isError( ZSTD_initCDict_internal(cdict, dict, dictSize, + 1 /* byReference */, + dictMode, cParams) )) + return NULL; + + return cdict; } + #if 0 static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) { return ZSTD_getParamsFromCCtx(cdict->refContext); @@ -3997,10 +4060,12 @@ size_t ZSTD_initCStream_internal_opaque( return ERROR(memory_allocation); } ZSTD_freeCDict(zcs->cdictLocal); - /* TODO opaque version: what needs to be zero? */ - zcs->cdictLocal = ZSTD_createCDict_advanced_opaque( + + /* Is a CCtx_params version needed? */ + zcs->cdictLocal = ZSTD_createCDict_advanced( dict, dictSize, - params, zcs->customMem); + params.dictContentByRef, params.dictMode, + params.cParams, zcs->customMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); } else { diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index e7a05f4b1..02dad6c0b 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -746,11 +746,10 @@ size_t ZSTDMT_initCStream_internal_opaque( if (dict) { DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal); ZSTD_freeCDict(zcs->cdictLocal); - /* TODO: cctxParam version? Is this correct? - * by reference should be zero, mode should be ZSTD_dm_auto */ - zcs->cdictLocal = ZSTD_createCDict_advanced_opaque( - dict, dictSize, - cctxParams, zcs->cMem); + /* TODO: cctxParam version? Is this correct? */ + zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, + 0 /* byRef */, ZSTD_dm_auto, /* note : a loadPrefix becomes an internal CDict */ + cctxParams.cParams, zcs->cMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); } else { diff --git a/lib/zstd.h b/lib/zstd.h index 09b89911f..3e7574c78 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -527,11 +527,9 @@ ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t sr /*! ZSTD_estimate?DictSize() : * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). * ZSTD_estimateCStreamSize_advanced() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced(). - * ZSTD_estimateCDictSize_advanced_opaque() allows further compression parameters. ByReference can be set with ZSTD_CCtxParam_setParameter. * Note : dictionary created "byReference" are smaller */ ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference); -ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced_opaque(size_t dictSize, const ZSTD_CCtx_params* params); ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference); @@ -608,13 +606,6 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict( unsigned byReference, ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams); -ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( - void* workspace, size_t workspaceSize, - const void* dict, size_t dictSize, - const ZSTD_CCtx_params* params); - - - /*! ZSTD_getCParams() : * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. * `estimatedSrcSize` value is optional, select 0 if not known */ From 60e1bc617cd9cb2b254967b419d9f5dc194582c9 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Mon, 21 Aug 2017 15:39:37 -0700 Subject: [PATCH 031/248] Explicitly create a job cctxParam for multithreading --- lib/compress/zstdmt_compress.c | 42 +++++++++++++++------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 02dad6c0b..cf362a756 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -186,19 +186,17 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf) ZSTD_free(buf.start, bufPool->cMem); } -/** - * TODO - * - * Sets parameters to zero for jobs. Notably, nbThreads should be zero? - */ -static void ZSTDMT_zeroCCtxParams(ZSTD_CCtx_params* params) +/* TODO: Set relevant job parameters, initialize others to default. + * Notably, nbThreads should be zero. */ +static ZSTD_CCtx_params ZSTDMT_makeJobCCtxParams(ZSTD_CCtx_params const params) { - params->forceWindow = 0; - params->dictMode = (ZSTD_dictMode_e)(0); - params->dictContentByRef = 0; - params->nbThreads = 0; - params->jobSize = 0; - params->overlapSizeLog = 0; + ZSTD_CCtx_params jobParams; + memset(&jobParams, 0, sizeof(jobParams)); + + jobParams.cParams = params.cParams; + jobParams.fParams = params.fParams; + jobParams.compressionLevel = params.compressionLevel; + return jobParams; } /* ===== CCtx Pool ===== */ @@ -560,8 +558,7 @@ static size_t ZSTDMT_compress_advanced_opaque( unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbChunks : (unsigned)(dstCapacity / ZSTD_compressBound(avgChunkSize)); /* presumes avgChunkSize >= 256 KB, which should be the case */ size_t frameStartPos = 0, dstBufferPos = 0; XXH64_state_t xxh64; - ZSTD_CCtx_params requestedParams = cctxParams; - ZSTDMT_zeroCCtxParams(&requestedParams); + ZSTD_CCtx_params const requestedParams = ZSTDMT_makeJobCCtxParams(cctxParams); DEBUGLOG(4, "nbChunks : %2u (chunkSize : %u bytes) ", nbChunks, (U32)avgChunkSize); if (nbChunks==1) { /* fallback to single-thread mode */ @@ -720,19 +717,17 @@ size_t ZSTDMT_initCStream_internal_opaque( const ZSTD_CDict* cdict, ZSTD_CCtx_params cctxParams, unsigned long long pledgedSrcSize) { + ZSTD_CCtx_params const requestedParams = ZSTDMT_makeJobCCtxParams(cctxParams); DEBUGLOG(4, "ZSTDMT_initCStream_internal"); /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(cctxParams.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ - /* TODO: Set stuff to 0 to preserve old semantics. */ - ZSTDMT_zeroCCtxParams(&cctxParams); - if (zcs->nbThreads==1) { DEBUGLOG(4, "single thread mode"); return ZSTD_initCStream_internal_opaque(zcs->cctxPool->cctx[0], dict, dictSize, cdict, - cctxParams, pledgedSrcSize); + requestedParams, pledgedSrcSize); } if (zcs->allJobsCompleted == 0) { /* previous compression not correctly finished */ @@ -749,7 +744,7 @@ size_t ZSTDMT_initCStream_internal_opaque( /* TODO: cctxParam version? Is this correct? */ zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0 /* byRef */, ZSTD_dm_auto, /* note : a loadPrefix becomes an internal CDict */ - cctxParams.cParams, zcs->cMem); + requestedParams.cParams, zcs->cMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); } else { @@ -804,13 +799,12 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params params = ZSTD_getCCtxParamsFromCDict(cdict); + ZSTD_CCtx_params requestedParams = + ZSTDMT_makeJobCCtxParams(ZSTD_getCCtxParamsFromCDict(cdict)); if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */ - ZSTDMT_zeroCCtxParams(¶ms); - params.fParams = fParams; - + requestedParams.fParams = fParams; return ZSTDMT_initCStream_internal_opaque(mtctx, NULL, 0 /*dictSize*/, cdict, - params, pledgedSrcSize); + requestedParams, pledgedSrcSize); } From e50ed1fa3ac5857b6be914ec818a71c914789d4f Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Tue, 22 Aug 2017 11:55:42 -0700 Subject: [PATCH 032/248] Fix undefined behavior when srcSize==1 --- lib/common/bitstream.h | 33 ++++++++++++++++++--------------- lib/common/zstd_internal.h | 31 +++++++++++++++++-------------- lib/compress/zstd_compress.c | 3 ++- 3 files changed, 37 insertions(+), 30 deletions(-) diff --git a/lib/common/bitstream.h b/lib/common/bitstream.h index 06121f21c..c6f001248 100644 --- a/lib/common/bitstream.h +++ b/lib/common/bitstream.h @@ -169,25 +169,28 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); ****************************************************************/ MEM_STATIC unsigned BIT_highbit32 (register U32 val) { + assert(val != 0); + { # if defined(_MSC_VER) /* Visual */ - unsigned long r=0; - _BitScanReverse ( &r, val ); - return (unsigned) r; + unsigned long r=0; + _BitScanReverse ( &r, val ); + return (unsigned) r; # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ - return 31 - __builtin_clz (val); + return 31 - __builtin_clz (val); # else /* Software version */ - static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, - 11, 14, 16, 18, 22, 25, 3, 30, - 8, 12, 20, 28, 15, 17, 24, 7, - 19, 27, 23, 6, 26, 5, 4, 31 }; - U32 v = val; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27]; + static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, + 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, + 19, 27, 23, 6, 26, 5, 4, 31 }; + U32 v = val; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27]; # endif + } } /*===== Local Constants =====*/ diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 261052860..ac1f39896 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -268,24 +268,27 @@ void ZSTD_free(void* ptr, ZSTD_customMem customMem); MEM_STATIC U32 ZSTD_highbit32(U32 val) { + assert(val != 0); + { # if defined(_MSC_VER) /* Visual */ - unsigned long r=0; - _BitScanReverse(&r, val); - return (unsigned)r; + unsigned long r=0; + _BitScanReverse(&r, val); + return (unsigned)r; # elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */ - return 31 - __builtin_clz(val); + return 31 - __builtin_clz(val); # else /* Software version */ - static const int DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; - U32 v = val; - int r; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27]; - return r; + static const int DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; + U32 v = val; + int r; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27]; + return r; # endif + } } diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 0322c03eb..31e941596 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -497,7 +497,8 @@ ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameter { U32 const minSrcSize = (srcSize==0) ? 500 : 0; U64 const rSize = srcSize + dictSize + minSrcSize; if (rSize < ((U64)1< srcLog) cPar.windowLog = srcLog; } } if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog; From 6b2b6a9bd5676f15df702c1861990972a4d67141 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 22 Aug 2017 12:08:39 -0700 Subject: [PATCH 033/248] fixed extraordinary scenario where all fields use maximum possible nb of bits simultaneously can only happen if windowLog>=27 (level 22 --ultra) --- lib/compress/zstd_compress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 0322c03eb..66641e3d9 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -1131,7 +1131,7 @@ MEM_STATIC size_t ZSTD_encodeSequences(void* dst, size_t dstCapacity, BIT_addBits(&blockStream, sequences[n].litLength, llBits); if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream); BIT_addBits(&blockStream, sequences[n].matchLength, mlBits); - if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/ + if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream); if (longOffsets) { int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); if (extraBits) { From 8fd16367761528cd1f49bcd0ab58f73e70a2e29a Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Mon, 21 Aug 2017 18:10:44 -0700 Subject: [PATCH 034/248] Remove unused functions --- lib/common/zstd_internal.h | 4 +- lib/compress/zstd_compress.c | 200 +++------------------------------ lib/compress/zstdmt_compress.c | 12 +- tests/cctxParamRoundTrip.c | 2 + 4 files changed, 25 insertions(+), 193 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index ee3164183..4e56f6a92 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -348,12 +348,12 @@ MEM_STATIC U32 ZSTD_highbit32(U32 val) void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx); -/*! ZSTD_initCStream_internal_opaque() : +/*! ZSTD_initCStream_internal() : * Private use only. Init streaming operation. * expects params to be valid. * must receive dict, or cdict, or none, but not both. * @return : 0, or an error code */ -size_t ZSTD_initCStream_internal_opaque( +size_t ZSTD_initCStream_internal( ZSTD_CStream* zcs, const void* dict, size_t dictSize, const ZSTD_CDict* cdict, diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 649cf8780..cfefe5c20 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -80,14 +80,8 @@ struct ZSTD_CCtx_s { U32 nextToUpdate3; /* index from which to continue dictionary update */ U32 hashLog3; /* dispatch table : larger == faster, more memory */ U32 loadedDictEnd; /* index of end of dictionary */ -#if 0 - U32 forceWindow; /* force back-references to respect limit of 1<cdict) { return ERROR(stage_wrong); } - /* TODO: some parameters can be set even if cctx->cdict. - * They can be set directly using ZSTD_CCtx_setParameter? - */ - /* Assume the compression and frame parameters are validated */ cctx->requestedParams.cParams = params->cParams; cctx->requestedParams.fParams = params->fParams; @@ -3611,19 +3594,6 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcS /* ===== Dictionary API ===== */ -#if 0 -size_t ZSTD_estimateCDictSize_advanced_opaque( - size_t dictSize, const ZSTD_CCtx_params* params) -{ - if (params == NULL) { return 0; } - DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict)); - DEBUGLOG(5, "CCtx estimate : %u", - (U32)ZSTD_estimateCCtxSize_advanced_opaque(params)); - return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced_opaque(params) - + (params->dictContentByRef ? 0 : dictSize); - -} -#endif /*! ZSTD_estimateCDictSize_advanced() : * Estimate amount of memory that will be needed to create a dictionary with following arguments */ @@ -3650,45 +3620,6 @@ size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict); } -#if 0 -static ZSTD_parameters ZSTD_makeParams(ZSTD_compressionParameters cParams, ZSTD_frameParameters fParams) -{ - ZSTD_parameters params; - params.cParams = cParams; - params.fParams = fParams; - return params; -} -#endif - -#if 0 -static size_t ZSTD_initCDict_internal_opaque(ZSTD_CDict* cdict, - const void* dictBuffer, size_t dictSize, - ZSTD_CCtx_params params) -{ - DEBUGLOG(5, "ZSTD_initCDict_internal_opaque, mode %u", (U32)params.dictMode); - if ((params.dictContentByRef) || (!dictBuffer) || (!dictSize)) { - cdict->dictBuffer = NULL; - cdict->dictContent = dictBuffer; - } else { - void* const internalBuffer = ZSTD_malloc(dictSize, cdict->refContext->customMem); - cdict->dictBuffer = internalBuffer; - cdict->dictContent = internalBuffer; - if (!internalBuffer) return ERROR(memory_allocation); - memcpy(internalBuffer, dictBuffer, dictSize); - } - cdict->dictContentSize = dictSize; - - /* TODO: do the frame parameters need to be zero? - * does nbThreads need to be zero? */ - CHECK_F( ZSTD_compressBegin_internal(cdict->refContext, - cdict->dictContent, dictSize, - NULL, - params, ZSTD_CONTENTSIZE_UNKNOWN, - ZSTDb_not_buffered) ); - return 0; -} -#endif - static size_t ZSTD_initCDict_internal( ZSTD_CDict* cdict, const void* dictBuffer, size_t dictSize, @@ -3710,6 +3641,7 @@ static size_t ZSTD_initCDict_internal( { ZSTD_frameParameters const fParams = { 0 /*contentSizeFlag */, 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */ + /* TODO: correct? */ ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams; cctxParams.fParams = fParams; cctxParams.cParams = cParams; @@ -3724,35 +3656,6 @@ static size_t ZSTD_initCDict_internal( return 0; } -#if 0 -/* Internal only */ -ZSTD_CDict* ZSTD_createCDict_advanced_opaque( - const void* dictBuffer, size_t dictSize, - ZSTD_CCtx_params params, ZSTD_customMem customMem) -{ - DEBUGLOG(5, "ZSTD_createCDict_advanced_opaque, mode %u", (U32)params.dictMode); - if (!customMem.customAlloc ^ !customMem.customFree) return NULL; - - { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); - ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem); - if (!cdict || !cctx) { - ZSTD_free(cdict, customMem); - ZSTD_freeCCtx(cctx); - return NULL; - } - cdict->refContext = cctx; - if (ZSTD_isError( ZSTD_initCDict_internal_opaque( - cdict, - dictBuffer, dictSize, - params) )) { - ZSTD_freeCDict(cdict); - return NULL; - } - return cdict; - } -} -#endif - ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference, ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams, ZSTD_customMem customMem) @@ -3807,45 +3710,6 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict) } } -#if 0 -ZSTD_CDict* ZSTD_initStaticCDict_advanced_opaque( - void *workspace, size_t workspaceSize, const void* dict, - size_t dictSize, - const ZSTD_CCtx_params* params) -{ - if (params == NULL) { return NULL; } - { ZSTD_CCtx_params cctxParams = *params; - size_t const cctxSize = ZSTD_estimateCCtxSize_advanced_opaque(params); - size_t const neededSize = sizeof(ZSTD_CDict) - + (cctxParams.dictContentByRef ? 0 : dictSize) - + cctxSize; - ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; - void* ptr; - DEBUGLOG(5, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7); - if ((size_t)workspace & 7) return NULL; /* 8-aligned */ - DEBUGLOG(5, "(workspaceSize < neededSize) : (%u < %u) => %u", - (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize)); - if (workspaceSize < neededSize) return NULL; - - if (!cctxParams.dictContentByRef) { - memcpy(cdict+1, dict, dictSize); - dict = cdict+1; - ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize; - } else { - ptr = cdict+1; - } - cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize); - cctxParams.dictContentByRef = 1; - - /* What if nbThreads > 1? */ - if (ZSTD_isError( ZSTD_initCDict_internal_opaque(cdict, dict, dictSize, cctxParams) )) - return NULL; - - return cdict; - } -} -#endif - /*! ZSTD_initStaticCDict_advanced() : * Generate a digested dictionary in provided memory area. * workspace: The memory area to emplace the dictionary into. @@ -3893,12 +3757,6 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, return cdict; } -#if 0 -static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) { - return ZSTD_getParamsFromCCtx(cdict->refContext); -}a -#endif - ZSTD_CCtx_params ZSTD_getCCtxParamsFromCDict(const ZSTD_CDict* cdict) { return cdict->refContext->appliedParams; } @@ -3910,7 +3768,7 @@ size_t ZSTD_compressBegin_usingCDict_advanced( ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) { if (cdict==NULL) return ERROR(dictionary_wrong); - { ZSTD_CCtx_params params = cdict->refContext->appliedParams; + { ZSTD_CCtx_params params = ZSTD_getCCtxParamsFromCDict(cdict); params.fParams = fParams; params.dictMode = ZSTD_dm_auto; DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced"); @@ -3992,7 +3850,7 @@ size_t ZSTD_CStreamOutSize(void) return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; } -static size_t ZSTD_resetCStream_internal_opaque( +static size_t ZSTD_resetCStream_internal( ZSTD_CStream* zcs, const void* dict, size_t dictSize, const ZSTD_CDict* cdict, @@ -4018,20 +3876,6 @@ static size_t ZSTD_resetCStream_internal_opaque( return 0; /* ready to go */ } -#if 0 -static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, - const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, - const ZSTD_CDict* cdict, - ZSTD_parameters params, unsigned long long pledgedSrcSize) -{ - ZSTD_CCtx_params cctxParams = zcs->requestedParams; - cctxParams.cParams = params.cParams; - cctxParams.fParams = params.fParams; - return ZSTD_resetCStream_internal_opaque(zcs, dict, dictSize, - cdict, cctxParams, pledgedSrcSize); -} -#endif - size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) { ZSTD_CCtx_params params = zcs->requestedParams; @@ -4040,10 +3884,14 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) if (params.compressionLevel != ZSTD_CLEVEL_CUSTOM) { params.cParams = ZSTD_getCParams(params.compressionLevel, pledgedSrcSize, 0 /* dictSize */); } - return ZSTD_resetCStream_internal_opaque(zcs, NULL, 0, zcs->cdict, params, pledgedSrcSize); + return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->cdict, params, pledgedSrcSize); } -size_t ZSTD_initCStream_internal_opaque( +/*! ZSTD_initCStream_internal() : + * Note : not static (but hidden) (not exposed). Used by zstdmt_compress.c + * Assumption 1 : params are valid + * Assumption 2 : either dict, or cdict, is defined, not both */ +size_t ZSTD_initCStream_internal( ZSTD_CStream* zcs, const void* dict, size_t dictSize, const ZSTD_CDict* cdict, @@ -4079,28 +3927,10 @@ size_t ZSTD_initCStream_internal_opaque( } zcs->requestedParams = params; - return ZSTD_resetCStream_internal_opaque( + return ZSTD_resetCStream_internal( zcs, NULL, 0, zcs->cdict, params, pledgedSrcSize); } -#if 0 -/*! ZSTD_initCStream_internal() : - * Note : not static, but hidden (not exposed). Used by zstdmt_compress.c - * Assumption 1 : params are valid - * Assumption 2 : either dict, or cdict, is defined, not both */ -static size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, - const void* dict, size_t dictSize, const ZSTD_CDict* cdict, - ZSTD_parameters params, unsigned long long pledgedSrcSize) -{ - ZSTD_CCtx_params cctxParams = zcs->requestedParams; - cctxParams.cParams = params.cParams; - cctxParams.fParams = params.fParams; - cctxParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; - return ZSTD_initCStream_internal_opaque(zcs, dict, dictSize, cdict, - cctxParams, pledgedSrcSize); -} -#endif - /* ZSTD_initCStream_usingCDict_advanced() : * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, @@ -4112,7 +3942,7 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, { ZSTD_CCtx_params params = ZSTD_getCCtxParamsFromCDict(cdict); params.fParams = fParams; params.compressionLevel = ZSTD_CLEVEL_CUSTOM; - return ZSTD_initCStream_internal_opaque(zcs, + return ZSTD_initCStream_internal(zcs, NULL, 0, cdict, params, pledgedSrcSize); } @@ -4134,7 +3964,7 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, cctxParams.cParams = params.cParams; cctxParams.fParams = params.fParams; cctxParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; - return ZSTD_initCStream_internal_opaque(zcs, dict, dictSize, NULL, cctxParams, pledgedSrcSize); + return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, pledgedSrcSize); } size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) @@ -4144,7 +3974,7 @@ size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t di cctxParams.cParams = params.cParams; cctxParams.fParams = params.fParams; cctxParams.compressionLevel = compressionLevel; - return ZSTD_initCStream_internal_opaque(zcs, dict, dictSize, NULL, cctxParams, 0); + return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, 0); } size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize) @@ -4363,7 +4193,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, } else #endif { - CHECK_F( ZSTD_resetCStream_internal_opaque(cctx, prefix, prefixSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); + CHECK_F( ZSTD_resetCStream_internal(cctx, prefix, prefixSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); } } /* compression stage */ diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index cf362a756..ebedec904 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -186,12 +186,12 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf) ZSTD_free(buf.start, bufPool->cMem); } -/* TODO: Set relevant job parameters, initialize others to default. - * Notably, nbThreads should be zero. */ +/* Sets parameterse relevant to the compression job, initializing others to + * default values. Notably, nbThreads should probably be zero. */ static ZSTD_CCtx_params ZSTDMT_makeJobCCtxParams(ZSTD_CCtx_params const params) { ZSTD_CCtx_params jobParams; - memset(&jobParams, 0, sizeof(jobParams)); + memset(&jobParams, 0, sizeof(ZSTD_CCtx_params)); jobParams.cParams = params.cParams; jobParams.fParams = params.fParams; @@ -725,9 +725,9 @@ size_t ZSTDMT_initCStream_internal_opaque( if (zcs->nbThreads==1) { DEBUGLOG(4, "single thread mode"); - return ZSTD_initCStream_internal_opaque(zcs->cctxPool->cctx[0], - dict, dictSize, cdict, - requestedParams, pledgedSrcSize); + return ZSTD_initCStream_internal(zcs->cctxPool->cctx[0], + dict, dictSize, cdict, + requestedParams, pledgedSrcSize); } if (zcs->allJobsCompleted == 0) { /* previous compression not correctly finished */ diff --git a/tests/cctxParamRoundTrip.c b/tests/cctxParamRoundTrip.c index 906ad9cec..5ce47d4d1 100644 --- a/tests/cctxParamRoundTrip.c +++ b/tests/cctxParamRoundTrip.c @@ -70,6 +70,8 @@ static size_t roundTripTest(void* resultBuff, size_t resultBuffCapacity, ZSTD_outBuffer outBuffer = {compressedBuff, compressedBuffCapacity, 0 }; CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_compressionLevel, 1) ); + CHECK_Z (ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_nbThreads, 3) ); + CHECK_Z (ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_compressionStrategy, ZSTD_lazy) ); CHECK_Z( ZSTD_CCtx_applyCCtxParams(cctx, cctxParams) ); CHECK_Z (ZSTD_compress_generic(cctx, &outBuffer, &inBuffer, ZSTD_e_end) ); From 23fc0e41fac27cca8ff41a283238f29d190e5462 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Tue, 22 Aug 2017 14:24:47 -0700 Subject: [PATCH 035/248] Remove 'opaque' naming from internal functions --- lib/common/zstd_internal.h | 12 ++++---- lib/compress/zstd_compress.c | 26 ++++++++--------- lib/compress/zstdmt_compress.c | 52 +++++++++++++++------------------- 3 files changed, 42 insertions(+), 48 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 4e56f6a92..a68c7cbce 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -372,17 +372,17 @@ size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, ZSTD_CCtx_params ZSTD_getCCtxParamsFromCDict(const ZSTD_CDict* cdict); /* INTERNAL */ -size_t ZSTD_compressBegin_advanced_opaque(ZSTD_CCtx* cctx, +size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); /* INTERNAL */ -size_t ZSTD_compress_advanced_opaque(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const void* dict,size_t dictSize, - ZSTD_CCtx_params params); +size_t ZSTD_compress_advanced_internal(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + ZSTD_CCtx_params params); typedef struct { blockType_e blockType; diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index cfefe5c20..65081b239 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -3418,7 +3418,7 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, return ZSTD_compress_insertDictionary(cctx, dict, dictSize, params.dictMode); } -size_t ZSTD_compressBegin_advanced_opaque( +size_t ZSTD_compressBegin_advanced_internal( ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_CCtx_params params, @@ -3443,8 +3443,8 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, cctxParams.fParams = params.fParams; cctxParams.dictMode = ZSTD_dm_auto; - return ZSTD_compressBegin_advanced_opaque(cctx, dict, dictSize, cctxParams, - pledgedSrcSize); + return ZSTD_compressBegin_advanced_internal(cctx, dict, dictSize, cctxParams, + pledgedSrcSize); } @@ -3535,11 +3535,11 @@ static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, cctxParams.cParams = params.cParams; cctxParams.fParams = params.fParams; cctxParams.dictMode = ZSTD_dm_auto; - return ZSTD_compress_advanced_opaque(cctx, - dst, dstCapacity, - src, srcSize, - dict, dictSize, - cctxParams); + return ZSTD_compress_advanced_internal(cctx, + dst, dstCapacity, + src, srcSize, + dict, dictSize, + cctxParams); } size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, @@ -3553,7 +3553,7 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, } /* Internal */ -size_t ZSTD_compress_advanced_opaque( +size_t ZSTD_compress_advanced_internal( ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, @@ -3888,7 +3888,7 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) } /*! ZSTD_initCStream_internal() : - * Note : not static (but hidden) (not exposed). Used by zstdmt_compress.c + * Note : not static, but hidden (not exposed). Used by zstdmt_compress.c * Assumption 1 : params are valid * Assumption 2 : either dict, or cdict, is defined, not both */ size_t ZSTD_initCStream_internal( @@ -4154,12 +4154,12 @@ size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuf return ZSTD_compressStream_generic(zcs, output, input, ZSTD_e_continue); } -/*! ZSTDMT_initCStream_internal_opaque() : +/*! ZSTDMT_initCStream_internal() : * Private use only. Init streaming operation. * expects params to be valid. * must receive dict, or cdict, or none, but not both. * @return : 0, or an error code */ -size_t ZSTDMT_initCStream_internal_opaque(ZSTDMT_CCtx* zcs, +size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, const void* dict, size_t dictSize, const ZSTD_CDict* cdict, ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); @@ -4188,7 +4188,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, #ifdef ZSTD_MULTITHREAD if (params.nbThreads > 1) { DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", params.nbThreads); - CHECK_F( ZSTDMT_initCStream_internal_opaque(cctx->mtctx, prefix, prefixSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); + CHECK_F( ZSTDMT_initCStream_internal(cctx->mtctx, prefix, prefixSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); cctx->streamStage = zcss_load; } else #endif diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index ebedec904..4b8360933 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -342,7 +342,7 @@ void ZSTDMT_compressChunk(void* jobDescription) } else { /* srcStart points at reloaded section */ if (!job->firstChunk) job->params.fParams.contentSizeFlag = 0; /* ensure no srcSize control */ { size_t const dictModeError = ZSTD_setCCtxParameter(cctx, ZSTD_p_forceRawDict, 1); /* Force loading dictionary in "content-only" mode (no header analysis) */ - size_t const initError = ZSTD_compressBegin_advanced_opaque(cctx, job->srcStart, job->dictSize, job->params, job->fullFrameSize); + size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, job->srcStart, job->dictSize, job->params, job->fullFrameSize); if (ZSTD_isError(initError) || ZSTD_isError(dictModeError)) { job->cSize = initError; goto _endJob; } ZSTD_setCCtxParameter(cctx, ZSTD_p_forceWindow, 1); } } @@ -540,7 +540,7 @@ static unsigned computeNbChunks(size_t srcSize, unsigned windowLog, unsigned nbT return (multiplier>1) ? nbChunksLarge : nbChunksSmall; } -static size_t ZSTDMT_compress_advanced_opaque( +static size_t ZSTDMT_compress_advanced_internal( ZSTDMT_CCtx* mtctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, @@ -564,7 +564,7 @@ static size_t ZSTDMT_compress_advanced_opaque( if (nbChunks==1) { /* fallback to single-thread mode */ ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0]; if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, cctxParams.fParams); - return ZSTD_compress_advanced_opaque(cctx, dst, dstCapacity, src, srcSize, NULL, 0, requestedParams); + return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, NULL, 0, requestedParams); } assert(avgChunkSize >= 256 KB); /* condition for ZSTD_compressBound(A) + ZSTD_compressBound(B) <= ZSTD_compressBound(A+B), which is required for compressWithinDst */ ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(avgChunkSize) ); @@ -674,10 +674,10 @@ size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, ZSTD_CCtx_params cctxParams = mtctx->params; cctxParams.cParams = params.cParams; cctxParams.fParams = params.fParams; - return ZSTDMT_compress_advanced_opaque(mtctx, - dst, dstCapacity, - src, srcSize, - cdict, cctxParams, overlapLog); + return ZSTDMT_compress_advanced_internal(mtctx, + dst, dstCapacity, + src, srcSize, + cdict, cctxParams, overlapLog); } @@ -712,7 +712,7 @@ static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs) } } -size_t ZSTDMT_initCStream_internal_opaque( +size_t ZSTDMT_initCStream_internal( ZSTDMT_CCtx* zcs, const void* dict, size_t dictSize, const ZSTD_CDict* cdict, ZSTD_CCtx_params cctxParams, unsigned long long pledgedSrcSize) @@ -773,25 +773,17 @@ size_t ZSTDMT_initCStream_internal_opaque( return 0; } -/** ZSTDMT_initCStream_internal() */ -static size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, - const void* dict, size_t dictSize, const ZSTD_CDict* cdict, - ZSTD_parameters params, unsigned long long pledgedSrcSize) -{ - ZSTD_CCtx_params cctxParams = zcs->params; - cctxParams.cParams = params.cParams; - cctxParams.fParams = params.fParams; - return ZSTDMT_initCStream_internal_opaque(zcs, dict, dictSize, cdict, - cctxParams, pledgedSrcSize); -} - size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize) { + ZSTD_CCtx_params cctxParams = mtctx->params; DEBUGLOG(5, "ZSTDMT_initCStream_advanced"); - return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, NULL, params, pledgedSrcSize); + cctxParams.cParams = params.cParams; + cctxParams.fParams = params.fParams; + return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, NULL, + cctxParams, pledgedSrcSize); } size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, @@ -799,12 +791,11 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params requestedParams = - ZSTDMT_makeJobCCtxParams(ZSTD_getCCtxParamsFromCDict(cdict)); + ZSTD_CCtx_params requestedParams = ZSTD_getCCtxParamsFromCDict(cdict); if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */ requestedParams.fParams = fParams; - return ZSTDMT_initCStream_internal_opaque(mtctx, NULL, 0 /*dictSize*/, cdict, - requestedParams, pledgedSrcSize); + return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, cdict, + requestedParams, pledgedSrcSize); } @@ -814,13 +805,16 @@ size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* zcs, unsigned long long pledgedSrcSize) { if (zcs->nbThreads==1) return ZSTD_resetCStream(zcs->cctxPool->cctx[0], pledgedSrcSize); - return ZSTDMT_initCStream_internal_opaque(zcs, NULL, 0, 0, zcs->params, - pledgedSrcSize); + return ZSTDMT_initCStream_internal(zcs, NULL, 0, 0, zcs->params, + pledgedSrcSize); } size_t ZSTDMT_initCStream(ZSTDMT_CCtx* zcs, int compressionLevel) { ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0); - return ZSTDMT_initCStream_internal(zcs, NULL, 0, NULL, params, 0); + ZSTD_CCtx_params cctxParams = zcs->params; + cctxParams.cParams = params.cParams; + cctxParams.fParams = params.fParams; + return ZSTDMT_initCStream_internal(zcs, NULL, 0, NULL, cctxParams, 0); } @@ -973,7 +967,7 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, && (mtctx->inBuff.filled==0) /* nothing buffered */ && (endOp==ZSTD_e_end) /* end order */ && (output->size - output->pos >= ZSTD_compressBound(input->size - input->pos)) ) { /* enough room */ - size_t const cSize = ZSTDMT_compress_advanced_opaque(mtctx, + size_t const cSize = ZSTDMT_compress_advanced_internal(mtctx, (char*)output->dst + output->pos, output->size - output->pos, (const char*)input->src + input->pos, input->size - input->pos, mtctx->cdict, mtctx->params, mtctx->overlapLog); From 11303778d0fbc2559e7bf3e6b4f6b25b8748451a Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Tue, 22 Aug 2017 14:53:13 -0700 Subject: [PATCH 036/248] Add function to make cctxParams from ZSTD_parameters --- lib/compress/zstd_compress.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 65081b239..d6f50e60c 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -271,6 +271,15 @@ size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) return 0; } +static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( + ZSTD_CCtx_params cctxParams, ZSTD_parameters params) +{ + ZSTD_CCtx_params ret = cctxParams; + ret.cParams = params.cParams; + ret.fParams = params.fParams; + return ret; +} + static void ZSTD_cLevelToCCtxParams(ZSTD_CCtx_params* params) { if (params->compressionLevel == ZSTD_CLEVEL_CUSTOM) return; @@ -3438,11 +3447,9 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, ZSTD_parameters params, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params cctxParams = cctx->requestedParams; - cctxParams.cParams = params.cParams; - cctxParams.fParams = params.fParams; + ZSTD_CCtx_params cctxParams = + ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); cctxParams.dictMode = ZSTD_dm_auto; - return ZSTD_compressBegin_advanced_internal(cctx, dict, dictSize, cctxParams, pledgedSrcSize); } @@ -3531,9 +3538,8 @@ static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, const void* dict,size_t dictSize, ZSTD_parameters params) { - ZSTD_CCtx_params cctxParams = cctx->requestedParams; - cctxParams.cParams = params.cParams; - cctxParams.fParams = params.fParams; + ZSTD_CCtx_params cctxParams = + ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); cctxParams.dictMode = ZSTD_dm_auto; return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, @@ -3959,10 +3965,9 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params cctxParams = zcs->requestedParams; + ZSTD_CCtx_params cctxParams = + ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); CHECK_F( ZSTD_checkCParams(params.cParams) ); - cctxParams.cParams = params.cParams; - cctxParams.fParams = params.fParams; cctxParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, pledgedSrcSize); } @@ -3970,9 +3975,8 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) { ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); - ZSTD_CCtx_params cctxParams = zcs->requestedParams; - cctxParams.cParams = params.cParams; - cctxParams.fParams = params.fParams; + ZSTD_CCtx_params cctxParams = + ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); cctxParams.compressionLevel = compressionLevel; return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, 0); } From 20f715d70971e77c892feeaaf8868ea06da9bd42 Mon Sep 17 00:00:00 2001 From: Dmitriy Titarenko Date: Wed, 23 Aug 2017 15:56:15 +0500 Subject: [PATCH 037/248] Fix displayLevel overflow --- lib/dictBuilder/cover.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index 117acbf7b..61497846b 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -969,7 +969,7 @@ ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover( /* Initialization */ COVER_best_init(&best); /* Turn down global display level to clean up display at level 2 and below */ - g_displayLevel = parameters->zParams.notificationLevel - 1; + g_displayLevel = displayLevel == 0 ? 0 : displayLevel - 1; /* Loop through d first because each new value needs a new context */ LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n", kIterations); From 6f1a21c7e9a41adbecba62b3f9e7eb6741f0eaef Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Wed, 23 Aug 2017 10:24:19 -0700 Subject: [PATCH 038/248] Remove formatting-only changes --- lib/common/zstd_internal.h | 1 - lib/compress/zstd_compress.c | 53 +++--- lib/compress/zstdmt_compress.c | 4 +- lib/zstd.h | 3 +- programs/fileio.c | 1 + tests/zstreamtest.c | 293 +-------------------------------- 6 files changed, 28 insertions(+), 327 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index a68c7cbce..53631b936 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -304,7 +304,6 @@ struct ZSTD_CCtx_params_s { unsigned overlapSizeLog; }; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */ - const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); void ZSTD_seqToCodes(const seqStore_t* seqStorePtr); diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index d6f50e60c..d1d321011 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -215,6 +215,7 @@ size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned } } + #define ZSTD_CLEVEL_CUSTOM 999 static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx) { @@ -3151,10 +3152,8 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */ if (frame && (cctx->stage==ZSTDcs_init)) { - fhSize = ZSTD_writeFrameHeader( - dst, dstCapacity, - cctx->appliedParams, - cctx->pledgedSrcSizePlusOne-1, cctx->dictID); + fhSize = ZSTD_writeFrameHeader(dst, dstCapacity,cctx->appliedParams, + cctx->pledgedSrcSizePlusOne-1, cctx->dictID); if (ZSTD_isError(fhSize)) return fhSize; dstCapacity -= fhSize; dst = (char*)dst + fhSize; @@ -3444,8 +3443,7 @@ size_t ZSTD_compressBegin_advanced_internal( * @return : 0, or an error code */ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, - ZSTD_parameters params, - unsigned long long pledgedSrcSize) + ZSTD_parameters params, unsigned long long pledgedSrcSize) { ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); @@ -3571,11 +3569,8 @@ size_t ZSTD_compress_advanced_internal( return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); } -size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, - size_t dstCapacity, - const void* src, size_t srcSize, - const void* dict, size_t dictSize, - int compressionLevel) +size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, + const void* dict, size_t dictSize, int compressionLevel) { ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0); params.fParams.contentSizeFlag = 1; @@ -3606,8 +3601,7 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcS size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference) { DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict)); - DEBUGLOG(5, "CCtx estimate : %u", - (U32)ZSTD_estimateCCtxSize_advanced(cParams)); + DEBUGLOG(5, "CCtx estimate : %u", (U32)ZSTD_estimateCCtxSize_advanced(cParams)); return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced(cParams) + (byReference ? 0 : dictSize); } @@ -3645,7 +3639,7 @@ static size_t ZSTD_initCDict_internal( } cdict->dictContentSize = dictSize; - { ZSTD_frameParameters const fParams = { 0 /*contentSizeFlag */, + { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */ /* TODO: correct? */ ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams; @@ -3666,7 +3660,7 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference, ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams, ZSTD_customMem customMem) { - DEBUGLOG(5, "ZSTD_createCDict_advanced, mode %u", dictMode); + DEBUGLOG(5, "ZSTD_createCDict_advanced, mode %u", (U32)dictMode); if (!customMem.customAlloc ^ !customMem.customFree) return NULL; { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); @@ -3677,8 +3671,7 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, return NULL; } cdict->refContext = cctx; - if (ZSTD_isError( ZSTD_initCDict_internal( - cdict, + if (ZSTD_isError( ZSTD_initCDict_internal(cdict, dictBuffer, dictSize, byReference, dictMode, cParams) )) { @@ -3735,8 +3728,7 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, ZSTD_compressionParameters cParams) { size_t const cctxSize = ZSTD_estimateCCtxSize_advanced(cParams); - size_t const neededSize = sizeof(ZSTD_CDict) - + (byReference ? 0 : dictSize) + size_t const neededSize = sizeof(ZSTD_CDict) + (byReference ? 0 : dictSize) + cctxSize; ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; void* ptr; @@ -3755,9 +3747,10 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, } cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize); - if (ZSTD_isError( ZSTD_initCDict_internal(cdict, dict, dictSize, - 1 /* byReference */, - dictMode, cParams) )) + if (ZSTD_isError( ZSTD_initCDict_internal(cdict, + dict, dictSize, + 1 /* byReference */, dictMode, + cParams) )) return NULL; return cdict; @@ -3897,12 +3890,10 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) * Note : not static, but hidden (not exposed). Used by zstdmt_compress.c * Assumption 1 : params are valid * Assumption 2 : either dict, or cdict, is defined, not both */ -size_t ZSTD_initCStream_internal( - ZSTD_CStream* zcs, - const void* dict, size_t dictSize, - const ZSTD_CDict* cdict, - ZSTD_CCtx_params params, - unsigned long long pledgedSrcSize) +size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + const ZSTD_CDict* cdict, + ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) { assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ @@ -3931,10 +3922,10 @@ size_t ZSTD_initCStream_internal( zcs->cdictLocal = NULL; zcs->cdict = cdict; } + zcs->requestedParams = params; - return ZSTD_resetCStream_internal( - zcs, NULL, 0, zcs->cdict, params, pledgedSrcSize); + return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->cdict, params, pledgedSrcSize); } /* ZSTD_initCStream_usingCDict_advanced() : @@ -4167,6 +4158,7 @@ size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, const void* dict, size_t dictSize, const ZSTD_CDict* cdict, ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); + size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input, @@ -4182,7 +4174,6 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, const void* const prefix = cctx->prefix; size_t const prefixSize = cctx->prefixSize; ZSTD_CCtx_params params = cctx->requestedParams; - if (params.compressionLevel != ZSTD_CLEVEL_CUSTOM) params.cParams = ZSTD_getCParams(params.compressionLevel, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 4b8360933..a52cb8aa0 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -62,7 +62,7 @@ static unsigned long long GetCurrentClockTimeMicroseconds(void) DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, "Thread took %llu microseconds to acquire mutex %s \n", \ elapsedTime, #mutex); \ } } \ - } else { pthread_mutex_lock(mutex); } \ + } else pthread_mutex_lock(mutex); \ } #else @@ -743,7 +743,7 @@ size_t ZSTDMT_initCStream_internal( ZSTD_freeCDict(zcs->cdictLocal); /* TODO: cctxParam version? Is this correct? */ zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, - 0 /* byRef */, ZSTD_dm_auto, /* note : a loadPrefix becomes an internal CDict */ + 0 /* byRef */, ZSTD_dm_auto, /* note : a loadPrefix becomes an internal CDict */ requestedParams.cParams, zcs->cMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); diff --git a/lib/zstd.h b/lib/zstd.h index 3e7574c78..e207e46bf 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -987,7 +987,7 @@ typedef enum { /* advanced parameters - may not remain available after API update */ ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize, - * even when referencing into Dictionary content (default:0) */ + * even when referencing into Dictionary content (default:0) */ } ZSTD_cParameter; @@ -1101,6 +1101,7 @@ size_t ZSTD_compress_generic_simpleArgs ( const void* src, size_t srcSize, size_t* srcPos, ZSTD_EndDirective endOp); + /** ZSTD_CCtx_params : * * - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure diff --git a/programs/fileio.c b/programs/fileio.c index 669052d8b..1dd8008e8 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -214,6 +214,7 @@ void FIO_setOverlapLog(unsigned overlapLog){ g_overlapLog = overlapLog; } + /*-************************************* * Functions ***************************************/ diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 8f974b461..98e121949 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1204,298 +1204,6 @@ _output_error: goto _cleanup; } - -/* Tests for ZSTD_compress_generic() API */ -#if 0 -static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests) -{ - U32 const maxSrcLog = bigTests ? 24 : 22; - static const U32 maxSampleLog = 19; - size_t const srcBufferSize = (size_t)1<= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); } - else { DISPLAYUPDATE(2, "\r%6u ", testNb); } - FUZ_rand(&coreSeed); - lseed = coreSeed ^ prime32; - - /* states full reset (deliberately not synchronized) */ - /* some issues can only happen when reusing states */ - if ((FUZ_rand(&lseed) & 0xFF) == 131) { - DISPLAYLEVEL(5, "Creating new context \n"); - ZSTD_freeCCtx(zc); - zc = ZSTD_createCCtx(); - CHECK(zc==NULL, "ZSTD_createCCtx allocation error"); - resetAllowed=0; - } - if ((FUZ_rand(&lseed) & 0xFF) == 132) { - ZSTD_freeDStream(zd); - zd = ZSTD_createDStream(); - CHECK(zd==NULL, "ZSTD_createDStream allocation error"); - ZSTD_initDStream_usingDict(zd, NULL, 0); /* ensure at least one init */ - } - - /* srcBuffer selection [0-4] */ - { U32 buffNb = FUZ_rand(&lseed) & 0x7F; - if (buffNb & 7) buffNb=2; /* most common : compressible (P) */ - else { - buffNb >>= 3; - if (buffNb & 7) { - const U32 tnb[2] = { 1, 3 }; /* barely/highly compressible */ - buffNb = tnb[buffNb >> 3]; - } else { - const U32 tnb[2] = { 0, 4 }; /* not compressible / sparse */ - buffNb = tnb[buffNb >> 3]; - } } - srcBuffer = cNoiseBuffer[buffNb]; - } - - /* compression init */ - CHECK_Z( ZSTD_CCtx_loadDictionary(zc, NULL, 0) ); /* cancel previous dict /*/ - if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */ - && oldTestLog /* at least one test happened */ && resetAllowed) { - maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2); - if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1; - { int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1; - CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_compressionLevel, compressionLevel) ); - } - } else { - U32 const testLog = FUZ_rand(&lseed) % maxSrcLog; - U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog; - U32 const cLevelCandidate = (FUZ_rand(&lseed) % - (ZSTD_maxCLevel() - - (MAX(testLog, dictLog) / 3))) + - 1; - U32 const cLevel = MIN(cLevelCandidate, cLevelMax); - maxTestSize = FUZ_rLogLength(&lseed, testLog); - oldTestLog = testLog; - /* random dictionary selection */ - dictSize = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0; - { size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize); - dict = srcBuffer + dictStart; - if (!dictSize) dict=NULL; - } - { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize; - ZSTD_compressionParameters cParams = ZSTD_getCParams(cLevel, pledgedSrcSize, dictSize); - - /* mess with compression parameters */ - cParams.windowLog += (FUZ_rand(&lseed) & 3) - 1; - cParams.hashLog += (FUZ_rand(&lseed) & 3) - 1; - cParams.chainLog += (FUZ_rand(&lseed) & 3) - 1; - cParams.searchLog += (FUZ_rand(&lseed) & 3) - 1; - cParams.searchLength += (FUZ_rand(&lseed) & 3) - 1; - cParams.targetLength = (U32)(cParams.targetLength * (0.5 + ((double)(FUZ_rand(&lseed) & 127) / 128))); - cParams = ZSTD_adjustCParams(cParams, 0, 0); - - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_windowLog, cParams.windowLog) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_hashLog, cParams.hashLog) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_chainLog, cParams.chainLog) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_searchLog, cParams.searchLog) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_minMatch, cParams.searchLength) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_targetLength, cParams.targetLength) ); - - /* unconditionally set, to be sync with decoder */ - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_refDictContent, FUZ_rand(&lseed) & 1) ); - if (FUZ_rand(&lseed) & 1) { - CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) ); - if (dict && dictSize) { - /* test that compression parameters are rejected (correctly) after loading a non-NULL dictionary */ - size_t const setError = ZSTD_CCtx_setParameter(zc, ZSTD_p_windowLog, cParams.windowLog-1) ; - CHECK(!ZSTD_isError(setError), "ZSTD_CCtx_setParameter should have failed"); - } } else { - CHECK_Z( ZSTD_CCtx_refPrefix(zc, dict, dictSize) ); - } - - /* mess with frame parameters */ - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_checksumFlag, FUZ_rand(&lseed) & 1) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_dictIDFlag, FUZ_rand(&lseed) & 1) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_contentSizeFlag, FUZ_rand(&lseed) & 1) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) ); - DISPLAYLEVEL(5, "pledgedSrcSize : %u \n", (U32)pledgedSrcSize); - - /* multi-threading parameters */ - { U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1; - U32 const nbThreads = MIN(nbThreadsCandidate, nbThreadsMax); - CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_nbThreads, nbThreads) ); - if (nbThreads > 1) { - U32 const jobLog = FUZ_rand(&lseed) % (testLog+1); - CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_overlapSizeLog, FUZ_rand(&lseed) % 10) ); - CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_jobSize, (U32)FUZ_rLogLength(&lseed, jobLog)) ); - } } } } - - /* multi-segments compression test */ - XXH64_reset(&xxhState, 0); - { ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ; - for (cSize=0, totalTestSize=0 ; (totalTestSize < maxTestSize) ; ) { - /* compress random chunks into randomly sized dst buffers */ - size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog); - size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize); - size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize); - size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1); - size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize); - ZSTD_EndDirective const flush = (FUZ_rand(&lseed) & 15) ? ZSTD_e_continue : ZSTD_e_flush; - ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 }; - outBuff.size = outBuff.pos + dstBuffSize; - - CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, flush) ); - DISPLAYLEVEL(5, "compress consumed %u bytes (total : %u) \n", - (U32)inBuff.pos, (U32)(totalTestSize + inBuff.pos)); - - XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos); - memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos); - totalTestSize += inBuff.pos; - } - - /* final frame epilogue */ - { size_t remainingToFlush = (size_t)(-1); - while (remainingToFlush) { - ZSTD_inBuffer inBuff = { NULL, 0, 0 }; - size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1); - size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize); - outBuff.size = outBuff.pos + adjustedDstSize; - DISPLAYLEVEL(5, "End-flush into dst buffer of size %u \n", (U32)adjustedDstSize); - remainingToFlush = ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end); - CHECK(ZSTD_isError(remainingToFlush), - "ZSTD_compress_generic w/ ZSTD_e_end error : %s", - ZSTD_getErrorName(remainingToFlush) ); - } } - crcOrig = XXH64_digest(&xxhState); - cSize = outBuff.pos; - DISPLAYLEVEL(5, "Frame completed : %u bytes \n", (U32)cSize); - } - - /* multi - fragments decompression test */ - if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) { - DISPLAYLEVEL(5, "resetting DCtx (dict:%08X) \n", (U32)(size_t)dict); - CHECK_Z( ZSTD_resetDStream(zd) ); - } else { - DISPLAYLEVEL(5, "using dict of size %u \n", (U32)dictSize); - CHECK_Z( ZSTD_initDStream_usingDict(zd, dict, dictSize) ); - } - { size_t decompressionResult = 1; - ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 }; - ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 }; - for (totalGenSize = 0 ; decompressionResult ; ) { - size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog); - size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog); - size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize); - inBuff.size = inBuff.pos + readCSrcSize; - outBuff.size = inBuff.pos + dstBuffSize; - DISPLAYLEVEL(5, "ZSTD_decompressStream input %u bytes (pos:%u/%u)\n", - (U32)readCSrcSize, (U32)inBuff.pos, (U32)cSize); - decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff); - CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult)); - DISPLAYLEVEL(5, "inBuff.pos = %u \n", (U32)readCSrcSize); - } - CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (U32)outBuff.pos, (U32)totalTestSize); - CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (U32)inBuff.pos, (U32)cSize); - { U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0); - if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize); - CHECK (crcDest!=crcOrig, "decompressed data corrupted"); - } } - - /*===== noisy/erroneous src decompression test =====*/ - - /* add some noise */ - { U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2; - U32 nn; for (nn=0; nn Date: Wed, 23 Aug 2017 12:03:30 -0700 Subject: [PATCH 039/248] Add prototype support for customMem with cctxParams --- lib/common/zstd_internal.h | 4 ++ lib/compress/zstd_compress.c | 123 ++++++++++++++++++----------------- lib/zstd.h | 4 +- 3 files changed, 71 insertions(+), 60 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 53631b936..4e2403bee 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -302,6 +302,10 @@ struct ZSTD_CCtx_params_s { U32 nbThreads; unsigned jobSize; unsigned overlapSizeLog; + + /* For use with createCCtxParams() and freeCCtxParams() only */ + ZSTD_customMem customMem; + }; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index d1d321011..b375d369a 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -217,13 +217,22 @@ size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned #define ZSTD_CLEVEL_CUSTOM 999 +static void ZSTD_cLevelToCCtxParams_srcSize(ZSTD_CCtx_params* params, size_t srcSize) +{ + if (params->compressionLevel == ZSTD_CLEVEL_CUSTOM) return; + params->cParams = ZSTD_getCParams(params->compressionLevel, srcSize, 0); + params->compressionLevel = ZSTD_CLEVEL_CUSTOM; +} + static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx) { - if (cctx->requestedParams.compressionLevel==ZSTD_CLEVEL_CUSTOM) return; - cctx->requestedParams.cParams = - ZSTD_getCParams(cctx->requestedParams.compressionLevel, - cctx->pledgedSrcSizePlusOne-1, 0); - cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; + ZSTD_cLevelToCCtxParams_srcSize( + &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1); +} + +static void ZSTD_cLevelToCCtxParams(ZSTD_CCtx_params* params) +{ + ZSTD_cLevelToCCtxParams_srcSize(params, 0); } static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( @@ -236,16 +245,31 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( return cctxParams; } -ZSTD_CCtx_params* ZSTD_createCCtxParams(void) +static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced( + ZSTD_customMem customMem) { - ZSTD_CCtx_params* params = - (ZSTD_CCtx_params*)ZSTD_calloc(sizeof(ZSTD_CCtx_params), - ZSTD_defaultCMem); + ZSTD_CCtx_params* params; + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; + params = (ZSTD_CCtx_params*)ZSTD_calloc( + sizeof(ZSTD_CCtx_params), customMem); if (!params) { return NULL; } + params->customMem = customMem; params->compressionLevel = ZSTD_CLEVEL_DEFAULT; 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_free(params, params->customMem); + return 0; +} + size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params) { if (!params) { return ERROR(GENERIC); } @@ -265,13 +289,6 @@ size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) return 0; } -size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) -{ - if (params == NULL) { return 0; } - ZSTD_free(params, ZSTD_defaultCMem); - return 0; -} - static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( ZSTD_CCtx_params cctxParams, ZSTD_parameters params) { @@ -281,13 +298,6 @@ static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( return ret; } -static void ZSTD_cLevelToCCtxParams(ZSTD_CCtx_params* params) -{ - if (params->compressionLevel == ZSTD_CLEVEL_CUSTOM) return; - params->cParams = ZSTD_getCParams(params->compressionLevel, 0, 0); - params->compressionLevel = ZSTD_CLEVEL_CUSTOM; -} - #define CLAMPCHECK(val,min,max) { \ if (((val)<(min)) | ((val)>(max))) { \ return ERROR(parameter_outOfBound); \ @@ -311,7 +321,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v case ZSTD_p_minMatch: case ZSTD_p_targetLength: case ZSTD_p_compressionStrategy: - if (value == 0) return 0; + if (value == 0) return 0; /* special value : 0 means "don't change anything" */ if (cctx->cdict) return ERROR(stage_wrong); ZSTD_cLevelToCParams(cctx); /* Can optimize if srcSize is known */ return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); @@ -329,9 +339,8 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize, * even when referencing into Dictionary content * default : 0 when using a CDict, 1 when using a Prefix */ - cctx->requestedParams.forceWindow = value>0; cctx->loadedDictEnd = 0; - return 0; + return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); case ZSTD_p_nbThreads: if (value==0) return 0; @@ -521,7 +530,6 @@ static void ZSTD_debugPrintCCtxParams(ZSTD_CCtx_params* params) */ size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) { - if (params == NULL) { return ERROR(GENERIC); } if (cctx->cdict) { return ERROR(stage_wrong); } /* Assume the compression and frame parameters are validated */ @@ -545,6 +553,8 @@ size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params cctx, ZSTD_p_overlapSizeLog, params->overlapSizeLog) ); } + + /* customMem is used only for create/free params and can be ignored */ return 0; } @@ -693,32 +703,29 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u size_t ZSTD_estimateCCtxSize_advanced_opaque(const ZSTD_CCtx_params* params) { - if (params == NULL) { return 0; } - { ZSTD_compressionParameters const cParams = params->cParams; - size_t const blockSize = - MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); - U32 const divider = (cParams.searchLength==3) ? 3 : 4; - size_t const maxNbSeq = blockSize / divider; - size_t const tokenSpace = blockSize + 11*maxNbSeq; - size_t const chainSize = - (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog); - size_t const hSize = ((size_t)1) << cParams.hashLog; - U32 const hashLog3 = (cParams.searchLength>3) ? - 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog); - size_t const h3Size = ((size_t)1) << hashLog3; - size_t const entropySpace = sizeof(ZSTD_entropyCTables_t); - size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); + ZSTD_compressionParameters const cParams = params->cParams; + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); + U32 const divider = (cParams.searchLength==3) ? 3 : 4; + size_t const maxNbSeq = blockSize / divider; + size_t const tokenSpace = blockSize + 11*maxNbSeq; + size_t const chainSize = + (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog); + size_t const hSize = ((size_t)1) << cParams.hashLog; + U32 const hashLog3 = (cParams.searchLength>3) ? + 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog); + size_t const h3Size = ((size_t)1) << hashLog3; + size_t const entropySpace = sizeof(ZSTD_entropyCTables_t); + size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); - size_t const optBudget = - ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<cParams.windowLog); - size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize; - size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; - size_t const streamingSize = inBuffSize + outBuffSize; + size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced_opaque(params); + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog); + size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize; + size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; + size_t const streamingSize = inBuffSize + outBuffSize; - return CCtxSize + streamingSize; - } + return CCtxSize + streamingSize; } size_t ZSTD_estimateCStreamSize_advanced(ZSTD_compressionParameters cParams) diff --git a/lib/zstd.h b/lib/zstd.h index e207e46bf..4cff6974b 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -1111,7 +1111,9 @@ size_t ZSTD_compress_generic_simpleArgs ( * - ZSTD_CCtx_applyCCtxParams() : Apply parameters to an existing CCtx. These * parameters will be applied to all subsequent compression jobs. * - ZSTD_compress_generic() : Do compression using the CCtx. - * - ZSTD_freeCCtxParams() : Free the memory. */ + * - ZSTD_freeCCtxParams() : Free the memory. + * + * This can be used with ZSTD_estimateCCtxSize_opaque() for static allocation. */ ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); From 64ce49426bf4fb7873027f040a7a3fa1fd666563 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Wed, 23 Aug 2017 12:30:47 -0700 Subject: [PATCH 040/248] Fix cstream compression level --- lib/compress/zstd_compress.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index b375d369a..bfe021949 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -3457,14 +3457,16 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, pledgedSrcSize); } - size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) { ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); - return ZSTD_compressBegin_advanced(cctx, dict, dictSize, params, 0); + ZSTD_CCtx_params cctxParams = + ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); + cctxParams.dictMode = ZSTD_dm_auto; + return ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL, + cctxParams, 0, ZSTDb_not_buffered); } - size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel) { return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel); @@ -3928,6 +3930,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, zcs->cdict = cdict; } + params.compressionLevel = ZSTD_CLEVEL_CUSTOM; zcs->requestedParams = params; return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->cdict, params, pledgedSrcSize); @@ -3943,7 +3946,6 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, if (!cdict) return ERROR(dictionary_wrong); { ZSTD_CCtx_params params = ZSTD_getCCtxParamsFromCDict(cdict); params.fParams = fParams; - params.compressionLevel = ZSTD_CLEVEL_CUSTOM; return ZSTD_initCStream_internal(zcs, NULL, 0, cdict, params, pledgedSrcSize); @@ -3964,7 +3966,6 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); CHECK_F( ZSTD_checkCParams(params.cParams) ); - cctxParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, pledgedSrcSize); } @@ -3973,15 +3974,16 @@ size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t di ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); - cctxParams.compressionLevel = compressionLevel; return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, 0); } size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize) { + ZSTD_CCtx_params cctxParams; ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0); params.fParams.contentSizeFlag = (pledgedSrcSize>0); - return ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize); + cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); + return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, cctxParams, pledgedSrcSize); } size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) From 1c81f725ff7d8caa9136154fb2fdd19488f23083 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Wed, 23 Aug 2017 15:47:15 -0700 Subject: [PATCH 041/248] Remove duplicated testing code --- lib/compress/zstd_compress.c | 2 +- tests/Makefile | 7 +- tests/cctxParamRoundTrip.c | 205 ----------------------------------- tests/roundTripCrash.c | 79 +++++++++++--- 4 files changed, 67 insertions(+), 226 deletions(-) delete mode 100644 tests/cctxParamRoundTrip.c diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index bfe021949..40b6625fc 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -217,7 +217,7 @@ size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned #define ZSTD_CLEVEL_CUSTOM 999 -static void ZSTD_cLevelToCCtxParams_srcSize(ZSTD_CCtx_params* params, size_t srcSize) +static void ZSTD_cLevelToCCtxParams_srcSize(ZSTD_CCtx_params* params, U64 srcSize) { if (params->compressionLevel == ZSTD_CLEVEL_CUSTOM) return; params->cParams = ZSTD_getCParams(params->compressionLevel, srcSize, 0); diff --git a/tests/Makefile b/tests/Makefile index 228f4cdd2..3734f7737 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -169,11 +169,6 @@ datagen : $(PRGDIR)/datagen.c datagencli.c roundTripCrash : $(ZSTD_FILES) roundTripCrash.c $(CC) $(FLAGS) $^ -o $@$(EXT) -cctxParamRoundTrip : LDFLAGS += $(MULTITHREAD_CPP) -cctxParamRoundTrip : LDFLAGS += $(MULTITHREAD_LD) -cctxParamRoundTrip : $(ZSTD_FILES) cctxParamRoundTrip.c - $(CC) $(FLAGS) $^ -o $@$(EXT) - longmatch : $(ZSTD_FILES) longmatch.c $(CC) $(FLAGS) $^ -o $@$(EXT) @@ -217,7 +212,7 @@ clean: fuzzer$(EXT) fuzzer32$(EXT) zbufftest$(EXT) zbufftest32$(EXT) \ fuzzer-dll$(EXT) zstreamtest-dll$(EXT) zbufftest-dll$(EXT)\ zstreamtest$(EXT) zstreamtest32$(EXT) \ - datagen$(EXT) paramgrill$(EXT) roundTripCrash$(EXT) cctxParamRoundTrip$(EXT) longmatch$(EXT) \ + datagen$(EXT) paramgrill$(EXT) roundTripCrash$(EXT) longmatch$(EXT) \ symbols$(EXT) invalidDictionaries$(EXT) legacy$(EXT) poolTests$(EXT) \ decodecorpus$(EXT) @echo Cleaning completed diff --git a/tests/cctxParamRoundTrip.c b/tests/cctxParamRoundTrip.c deleted file mode 100644 index 5ce47d4d1..000000000 --- a/tests/cctxParamRoundTrip.c +++ /dev/null @@ -1,205 +0,0 @@ -/** - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -/* - This program takes a file in input, - performs a zstd round-trip test (compression - decompress) - compares the result with original - and generates a crash (double free) on corruption detection. -*/ - -/*=========================================== -* Dependencies -*==========================================*/ -#include /* size_t */ -#include /* malloc, free, exit */ -#include /* fprintf */ -#include /* stat */ -#include /* stat */ -#include "xxhash.h" - -#define ZSTD_STATIC_LINKING_ONLY -#include "zstd.h" - -/*=========================================== -* Macros -*==========================================*/ -#define MIN(a,b) ( (a) < (b) ? (a) : (b) ) - -static void crash(int errorCode){ - /* abort if AFL/libfuzzer, exit otherwise */ - #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* could also use __AFL_COMPILER */ - abort(); - #else - exit(errorCode); - #endif -} - -#define CHECK_Z(f) { \ - size_t const err = f; \ - if (ZSTD_isError(err)) { \ - fprintf(stderr, \ - "Error=> %s: %s", \ - #f, ZSTD_getErrorName(err)); \ - crash(1); \ -} } - -/** roundTripTest() : -* Compresses `srcBuff` into `compressedBuff`, -* then decompresses `compressedBuff` into `resultBuff`. -* -* Parameters are currently set manually. -* -* @return : result of decompression, which should be == `srcSize` -* or an error code if either compression or decompression fails. -* Note : `compressedBuffCapacity` should be `>= ZSTD_compressBound(srcSize)` -* for compression to be guaranteed to work */ -static size_t roundTripTest(void* resultBuff, size_t resultBuffCapacity, - void* compressedBuff, size_t compressedBuffCapacity, - const void* srcBuff, size_t srcBuffSize) -{ - ZSTD_CCtx* const cctx = ZSTD_createCCtx(); - ZSTD_CCtx_params* const cctxParams = ZSTD_createCCtxParams(); - ZSTD_inBuffer inBuffer = { srcBuff, srcBuffSize, 0 }; - ZSTD_outBuffer outBuffer = {compressedBuff, compressedBuffCapacity, 0 }; - - CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_compressionLevel, 1) ); - CHECK_Z (ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_nbThreads, 3) ); - CHECK_Z (ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_compressionStrategy, ZSTD_lazy) ); - CHECK_Z( ZSTD_CCtx_applyCCtxParams(cctx, cctxParams) ); - - CHECK_Z (ZSTD_compress_generic(cctx, &outBuffer, &inBuffer, ZSTD_e_end) ); - - ZSTD_freeCCtxParams(cctxParams); - ZSTD_freeCCtx(cctx); - - return ZSTD_decompress(resultBuff, resultBuffCapacity, compressedBuff, outBuffer.pos); -} - - -static size_t checkBuffers(const void* buff1, const void* buff2, size_t buffSize) -{ - const char* ip1 = (const char*)buff1; - const char* ip2 = (const char*)buff2; - size_t pos; - - for (pos=0; pos= `fileSize` */ -static void loadFile(void* buffer, const char* fileName, size_t fileSize) -{ - FILE* const f = fopen(fileName, "rb"); - if (isDirectory(fileName)) { - fprintf(stderr, "Ignoring %s directory \n", fileName); - exit(2); - } - if (f==NULL) { - fprintf(stderr, "Impossible to open %s \n", fileName); - exit(3); - } - { size_t const readSize = fread(buffer, 1, fileSize, f); - if (readSize != fileSize) { - fprintf(stderr, "Error reading %s \n", fileName); - exit(5); - } } - fclose(f); -} - - -static void fileCheck(const char* fileName) -{ - size_t const fileSize = getFileSize(fileName); - void* buffer = malloc(fileSize); - if (!buffer) { - fprintf(stderr, "not enough memory \n"); - exit(4); - } - loadFile(buffer, fileName, fileSize); - roundTripCheck(buffer, fileSize); - free (buffer); -} - -int main(int argCount, const char** argv) { - if (argCount < 2) { - fprintf(stderr, "Error : no argument : need input file \n"); - exit(9); - } - fileCheck(argv[1]); - fprintf(stderr, "no pb detected\n"); - return 0; -} diff --git a/tests/roundTripCrash.c b/tests/roundTripCrash.c index 77c6737ee..fb14fa87b 100644 --- a/tests/roundTripCrash.c +++ b/tests/roundTripCrash.c @@ -20,9 +20,12 @@ #include /* size_t */ #include /* malloc, free, exit */ #include /* fprintf */ +#include /* strcmp */ #include /* stat */ #include /* stat */ #include "xxhash.h" + +#define ZSTD_STATIC_LINKING_ONLY #include "zstd.h" /*=========================================== @@ -30,6 +33,24 @@ *==========================================*/ #define MIN(a,b) ( (a) < (b) ? (a) : (b) ) +static void crash(int errorCode){ + /* abort if AFL/libfuzzer, exit otherwise */ + #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* could also use __AFL_COMPILER */ + abort(); + #else + exit(errorCode); + #endif +} + +#define CHECK_Z(f) { \ + size_t const err = f; \ + if (ZSTD_isError(err)) { \ + fprintf(stderr, \ + "Error=> %s: %s", \ + #f, ZSTD_getErrorName(err)); \ + crash(1); \ +} } + /** roundTripTest() : * Compresses `srcBuff` into `compressedBuff`, * then decompresses `compressedBuff` into `resultBuff`. @@ -54,6 +75,35 @@ static size_t roundTripTest(void* resultBuff, size_t resultBuffCapacity, return ZSTD_decompress(resultBuff, resultBuffCapacity, compressedBuff, cSize); } +/** cctxParamRoundTripTest() : + * Same as roundTripTest() except allows experimenting with ZSTD_CCtx_params. */ +static size_t cctxParamRoundTripTest(void* resultBuff, size_t resultBuffCapacity, + void* compressedBuff, size_t compressedBuffCapacity, + const void* srcBuff, size_t srcBuffSize) +{ + ZSTD_CCtx* const cctx = ZSTD_createCCtx(); + ZSTD_CCtx_params* const cctxParams = ZSTD_createCCtxParams(); + ZSTD_inBuffer inBuffer = { srcBuff, srcBuffSize, 0 }; + ZSTD_outBuffer outBuffer = {compressedBuff, compressedBuffCapacity, 0 }; + + static const int maxClevel = 19; + size_t const hashLength = MIN(128, srcBuffSize); + unsigned const h32 = XXH32(srcBuff, hashLength, 0); + int const cLevel = h32 % maxClevel; + + /* Set parameters */ + CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_compressionLevel, cLevel) ); + + /* Apply parameters */ + CHECK_Z( ZSTD_CCtx_applyCCtxParams(cctx, cctxParams) ); + + CHECK_Z (ZSTD_compress_generic(cctx, &outBuffer, &inBuffer, ZSTD_e_end) ); + + ZSTD_freeCCtxParams(cctxParams); + ZSTD_freeCCtx(cctx); + + return ZSTD_decompress(resultBuff, resultBuffCapacity, compressedBuff, outBuffer.pos); +} static size_t checkBuffers(const void* buff1, const void* buff2, size_t buffSize) { @@ -68,16 +118,7 @@ static size_t checkBuffers(const void* buff1, const void* buff2, size_t buffSize return pos; } -static void crash(int errorCode){ - /* abort if AFL/libfuzzer, exit otherwise */ - #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* could also use __AFL_COMPILER */ - abort(); - #else - exit(errorCode); - #endif -} - -static void roundTripCheck(const void* srcBuff, size_t srcBuffSize) +static void roundTripCheck(const void* srcBuff, size_t srcBuffSize, int testCCtxParams) { size_t const cBuffSize = ZSTD_compressBound(srcBuffSize); void* cBuff = malloc(cBuffSize); @@ -88,7 +129,9 @@ static void roundTripCheck(const void* srcBuff, size_t srcBuffSize) exit (1); } - { size_t const result = roundTripTest(rBuff, cBuffSize, cBuff, cBuffSize, srcBuff, srcBuffSize); + { size_t const result = testCCtxParams ? + cctxParamRoundTripTest(rBuff, cBuffSize, cBuff, cBuffSize, srcBuff, srcBuffSize) + : roundTripTest(rBuff, cBuffSize, cBuff, cBuffSize, srcBuff, srcBuffSize); if (ZSTD_isError(result)) { fprintf(stderr, "roundTripTest error : %s \n", ZSTD_getErrorName(result)); crash(1); @@ -162,7 +205,7 @@ static void loadFile(void* buffer, const char* fileName, size_t fileSize) } -static void fileCheck(const char* fileName) +static void fileCheck(const char* fileName, int testCCtxParams) { size_t const fileSize = getFileSize(fileName); void* buffer = malloc(fileSize); @@ -171,16 +214,24 @@ static void fileCheck(const char* fileName) exit(4); } loadFile(buffer, fileName, fileSize); - roundTripCheck(buffer, fileSize); + roundTripCheck(buffer, fileSize, testCCtxParams); free (buffer); } int main(int argCount, const char** argv) { + int argNb = 1; + int testCCtxParams = 0; if (argCount < 2) { fprintf(stderr, "Error : no argument : need input file \n"); exit(9); } - fileCheck(argv[1]); + + if (!strcmp(argv[argNb], "--cctxParams")) { + testCCtxParams = 1; + argNb++; + } + + fileCheck(argv[argNb], testCCtxParams); fprintf(stderr, "no pb detected\n"); return 0; } From bf3108fb50e0039a0fd15b3386366d40f0fd5a58 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Wed, 23 Aug 2017 17:03:31 -0700 Subject: [PATCH 042/248] Ensure zstdmt uses 'job version' of cctx parameters --- lib/compress/zstd_compress.c | 2 -- lib/compress/zstdmt_compress.c | 20 ++++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 40b6625fc..8bf01c905 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -3648,11 +3648,9 @@ static size_t ZSTD_initCDict_internal( { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */ - /* TODO: correct? */ ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams; cctxParams.fParams = fParams; cctxParams.cParams = cParams; - cctxParams.dictContentByRef = byReference; cctxParams.dictMode = dictMode; CHECK_F( ZSTD_compressBegin_internal(cdict->refContext, cdict->dictContent, dictSize, diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index a52cb8aa0..927fff472 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -548,9 +548,10 @@ static size_t ZSTDMT_compress_advanced_internal( ZSTD_CCtx_params const cctxParams, unsigned overlapLog) { + ZSTD_CCtx_params const requestedParams = ZSTDMT_makeJobCCtxParams(cctxParams); unsigned const overlapRLog = (overlapLog>9) ? 0 : 9-overlapLog; - size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (cctxParams.cParams.windowLog - overlapRLog); - unsigned nbChunks = computeNbChunks(srcSize, cctxParams.cParams.windowLog, mtctx->nbThreads); + size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (requestedParams.cParams.windowLog - overlapRLog); + unsigned nbChunks = computeNbChunks(srcSize, requestedParams.cParams.windowLog, mtctx->nbThreads); size_t const proposedChunkSize = (srcSize + (nbChunks-1)) / nbChunks; size_t const avgChunkSize = ((proposedChunkSize & 0x1FFFF) < 0x7FFF) ? proposedChunkSize + 0xFFFF : proposedChunkSize; /* avoid too small last block */ const char* const srcStart = (const char*)src; @@ -558,12 +559,11 @@ static size_t ZSTDMT_compress_advanced_internal( unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbChunks : (unsigned)(dstCapacity / ZSTD_compressBound(avgChunkSize)); /* presumes avgChunkSize >= 256 KB, which should be the case */ size_t frameStartPos = 0, dstBufferPos = 0; XXH64_state_t xxh64; - ZSTD_CCtx_params const requestedParams = ZSTDMT_makeJobCCtxParams(cctxParams); DEBUGLOG(4, "nbChunks : %2u (chunkSize : %u bytes) ", nbChunks, (U32)avgChunkSize); if (nbChunks==1) { /* fallback to single-thread mode */ ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0]; - if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, cctxParams.fParams); + if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, requestedParams.fParams); return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, NULL, 0, requestedParams); } assert(avgChunkSize >= 256 KB); /* condition for ZSTD_compressBound(A) + ZSTD_compressBound(B) <= ZSTD_compressBound(A+B), which is required for compressWithinDst */ @@ -605,7 +605,7 @@ static size_t ZSTDMT_compress_advanced_internal( mtctx->jobs[u].jobCompleted_mutex = &mtctx->jobCompleted_mutex; mtctx->jobs[u].jobCompleted_cond = &mtctx->jobCompleted_cond; - if (cctxParams.fParams.checksumFlag) { + if (requestedParams.fParams.checksumFlag) { XXH64_update(&xxh64, srcStart + frameStartPos, chunkSize); } @@ -648,8 +648,8 @@ static size_t ZSTDMT_compress_advanced_internal( } } /* for (chunkID=0; chunkID dstCapacity) { error = ERROR(dstSize_tooSmall); @@ -720,7 +720,7 @@ size_t ZSTDMT_initCStream_internal( ZSTD_CCtx_params const requestedParams = ZSTDMT_makeJobCCtxParams(cctxParams); DEBUGLOG(4, "ZSTDMT_initCStream_internal"); /* params are supposed to be fully validated at this point */ - assert(!ZSTD_isError(ZSTD_checkCParams(cctxParams.cParams))); + assert(!ZSTD_isError(ZSTD_checkCParams(requestedParams.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ if (zcs->nbThreads==1) { @@ -736,7 +736,7 @@ size_t ZSTDMT_initCStream_internal( zcs->allJobsCompleted = 1; } - zcs->params = cctxParams; + zcs->params = requestedParams; zcs->frameContentSize = pledgedSrcSize; if (dict) { DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal); @@ -769,7 +769,7 @@ size_t ZSTDMT_initCStream_internal( zcs->nextJobID = 0; zcs->frameEnded = 0; zcs->allJobsCompleted = 0; - if (cctxParams.fParams.checksumFlag) XXH64_reset(&zcs->xxhState, 0); + if (requestedParams.fParams.checksumFlag) XXH64_reset(&zcs->xxhState, 0); return 0; } From fd9bf425160fbfd58ecac5da1058b28fcb88641a Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Wed, 23 Aug 2017 19:11:05 -0700 Subject: [PATCH 043/248] Fix forceWindow and dictMode setting for zstdmt jobs --- lib/compress/zstdmt_compress.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 927fff472..6661e0a73 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -341,10 +341,21 @@ void ZSTDMT_compressChunk(void* jobDescription) if (ZSTD_isError(initError)) { job->cSize = initError; goto _endJob; } } else { /* srcStart points at reloaded section */ if (!job->firstChunk) job->params.fParams.contentSizeFlag = 0; /* ensure no srcSize control */ - { size_t const dictModeError = ZSTD_setCCtxParameter(cctx, ZSTD_p_forceRawDict, 1); /* Force loading dictionary in "content-only" mode (no header analysis) */ - size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, job->srcStart, job->dictSize, job->params, job->fullFrameSize); - if (ZSTD_isError(initError) || ZSTD_isError(dictModeError)) { job->cSize = initError; goto _endJob; } - ZSTD_setCCtxParameter(cctx, ZSTD_p_forceWindow, 1); + { ZSTD_CCtx_params jobParams = job->params; + /* Force loading dictionary in "content-only" mode (no header analysis) */ + size_t const dictModeError = + ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_dictMode, 1); + size_t const forceWindowError = + ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk); + /* TODO: new/old api do not interact well here (or with + * ZSTD_setCCtxParameter). + * ZSTD_compressBegin_advanced copies params directly to + * appliedParams. ZSTD_CCtx_setParameter sets params in requested + * parameters. They should not be mixed -- parameters should be passed + * directly */ + size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, job->srcStart, job->dictSize, jobParams, job->fullFrameSize); + if (ZSTD_isError(initError) || ZSTD_isError(dictModeError) || + ZSTD_isError(forceWindowError)) { job->cSize = initError; goto _endJob; } } } if (!job->firstChunk) { /* flush and overwrite frame header when it's not first segment */ size_t const hSize = ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, 0); From 2fbf0285b2a1ac16e18007889b9422d88dfbdffc Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Thu, 24 Aug 2017 11:25:41 -0700 Subject: [PATCH 044/248] Fix interaction with ZSTD_setCCtxParameter() and cleanup --- lib/compress/zstd_compress.c | 35 ++++------------------------------ lib/compress/zstdmt_compress.c | 12 ++++-------- 2 files changed, 8 insertions(+), 39 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 8bf01c905..f3f602230 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -198,18 +198,22 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } /* older variant; will be deprecated */ +/* Both requested and applied params need to be set as this function can be + * called before/after ZSTD_parameters have been applied. */ size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value) { switch(param) { case ZSTD_p_forceWindow : cctx->requestedParams.forceWindow = value>0; + cctx->appliedParams.forceWindow = value>0; cctx->loadedDictEnd = 0; return 0; ZSTD_STATIC_ASSERT(ZSTD_dm_auto==0); ZSTD_STATIC_ASSERT(ZSTD_dm_rawContent==1); case ZSTD_p_forceRawDict : cctx->requestedParams.dictMode = (ZSTD_dictMode_e)(value>0); + cctx->appliedParams.dictMode = (ZSTD_dictMode_e)(value>0); return 0; default: return ERROR(parameter_unsupported); } @@ -491,35 +495,6 @@ size_t ZSTD_CCtxParam_setParameter( } } -#if 0 -static void ZSTD_debugPrintCCtxParams(ZSTD_CCtx_params* params) -{ - DEBUGLOG(2, "======CCtxParams======"); - DEBUGLOG(2, "cParams: %u %u %u %u %u %u %u", - params->cParams.windowLog, - params->cParams.chainLog, - params->cParams.hashLog, - params->cParams.searchLog, - params->cParams.searchLength, - params->cParams.targetLength, - params->cParams.strategy); - DEBUGLOG(2, "fParams: %u %u %u", - params->fParams.contentSizeFlag, - params->fParams.checksumFlag, - params->fParams.noDictIDFlag); - DEBUGLOG(2, "cLevel, forceWindow: %u %u", - params->compressionLevel, - params->forceWindow); - DEBUGLOG(2, "dictionary: %u %u", - params->dictMode, - params->dictContentByRef); - DEBUGLOG(2, "multithreading: %u %u %u", - params->nbThreads, - params->jobSize, - params->overlapSizeLog); -} -#endif - /** * This function should be updated whenever ZSTD_CCtx_params is updated. * Parameters are copied manually before the dictionary is loaded. @@ -3910,8 +3885,6 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, return ERROR(memory_allocation); } ZSTD_freeCDict(zcs->cdictLocal); - - /* Is a CCtx_params version needed? */ zcs->cdictLocal = ZSTD_createCDict_advanced( dict, dictSize, params.dictContentByRef, params.dictMode, diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 6661e0a73..f7f02cfbb 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -186,7 +186,7 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf) ZSTD_free(buf.start, bufPool->cMem); } -/* Sets parameterse relevant to the compression job, initializing others to +/* Sets parameters relevant to the compression job, initializing others to * default values. Notably, nbThreads should probably be zero. */ static ZSTD_CCtx_params ZSTDMT_makeJobCCtxParams(ZSTD_CCtx_params const params) { @@ -347,12 +347,9 @@ void ZSTDMT_compressChunk(void* jobDescription) ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_dictMode, 1); size_t const forceWindowError = ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk); - /* TODO: new/old api do not interact well here (or with - * ZSTD_setCCtxParameter). - * ZSTD_compressBegin_advanced copies params directly to - * appliedParams. ZSTD_CCtx_setParameter sets params in requested - * parameters. They should not be mixed -- parameters should be passed - * directly */ + /* Note: ZSTD_setCCtxParameter() should not be used here. + * ZSTD_compressBegin_advanced_internal() copies the ZSTD_CCtx_params + * directly to appliedParams. */ size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, job->srcStart, job->dictSize, jobParams, job->fullFrameSize); if (ZSTD_isError(initError) || ZSTD_isError(dictModeError) || ZSTD_isError(forceWindowError)) { job->cSize = initError; goto _endJob; } @@ -752,7 +749,6 @@ size_t ZSTDMT_initCStream_internal( if (dict) { DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal); ZSTD_freeCDict(zcs->cdictLocal); - /* TODO: cctxParam version? Is this correct? */ zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0 /* byRef */, ZSTD_dm_auto, /* note : a loadPrefix becomes an internal CDict */ requestedParams.cParams, zcs->cMem); From 376f4359142d296cc78435ca72335bf25bc7854e Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 24 Aug 2017 14:45:06 -0700 Subject: [PATCH 045/248] [dictBuilder] Set default compression level to 3 --- lib/dictBuilder/zdict.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/dictBuilder/zdict.c b/lib/dictBuilder/zdict.c index c2871c2cc..8e6aa9c1c 100644 --- a/lib/dictBuilder/zdict.c +++ b/lib/dictBuilder/zdict.c @@ -60,7 +60,7 @@ #define NOISELENGTH 32 -static const int g_compressionLevel_default = 6; +static const int g_compressionLevel_default = 3; static const U32 g_selectivity_default = 9; @@ -703,7 +703,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, memset(repOffset, 0, sizeof(repOffset)); repOffset[1] = repOffset[4] = repOffset[8] = 1; memset(bestRepOffset, 0, sizeof(bestRepOffset)); - if (compressionLevel==0) compressionLevel = g_compressionLevel_default; + if (compressionLevel<=0) compressionLevel = g_compressionLevel_default; params = ZSTD_getParams(compressionLevel, averageSampleSize, dictBufferSize); { size_t const beginResult = ZSTD_compressBegin_advanced(esr.ref, dictBuffer, dictBufferSize, params, 0); if (ZSTD_isError(beginResult)) { @@ -1056,6 +1056,8 @@ size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity, memset(¶ms, 0, sizeof(params)); params.d = 8; params.steps = 4; + /* Default to level 6 since no compression level information is avaialble */ + params.zParams.compressionLevel = 6; return ZDICT_optimizeTrainFromBuffer_cover(dictBuffer, dictBufferCapacity, samplesBuffer, samplesSizes, nbSamples, ¶ms); From 15fdeb9e41306e8bb8d6a909a7be643768d75e6b Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Thu, 24 Aug 2017 16:28:49 -0700 Subject: [PATCH 046/248] Enforce nbThreads<=1 for estimateCCtxSize --- lib/compress/zstd_compress.c | 63 ++++++++++++++++++++---------------- lib/zstd.h | 7 ++-- tests/Makefile | 1 + 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index f3f602230..4513d9831 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -678,29 +678,34 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u size_t ZSTD_estimateCCtxSize_advanced_opaque(const ZSTD_CCtx_params* params) { - ZSTD_compressionParameters const cParams = params->cParams; - size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); - U32 const divider = (cParams.searchLength==3) ? 3 : 4; - size_t const maxNbSeq = blockSize / divider; - size_t const tokenSpace = blockSize + 11*maxNbSeq; - size_t const chainSize = - (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog); - size_t const hSize = ((size_t)1) << cParams.hashLog; - U32 const hashLog3 = (cParams.searchLength>3) ? - 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog); - size_t const h3Size = ((size_t)1) << hashLog3; - size_t const entropySpace = sizeof(ZSTD_entropyCTables_t); - size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); + /* Estimate CCtx size is supported for single-threaded compression only. */ + if (params->nbThreads > 1) { + return 0; + } + { ZSTD_compressionParameters const cParams = params->cParams; + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); + U32 const divider = (cParams.searchLength==3) ? 3 : 4; + size_t const maxNbSeq = blockSize / divider; + size_t const tokenSpace = blockSize + 11*maxNbSeq; + size_t const chainSize = + (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog); + size_t const hSize = ((size_t)1) << cParams.hashLog; + U32 const hashLog3 = (cParams.searchLength>3) ? + 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog); + size_t const h3Size = ((size_t)1) << hashLog3; + size_t const entropySpace = sizeof(ZSTD_entropyCTables_t); + size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); - size_t const optBudget = - ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<cParams.windowLog); - size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize; - size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; - size_t const streamingSize = inBuffSize + outBuffSize; + if (params->nbThreads > 1) { + return 0; + } + { size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced_opaque(params); + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog); + size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize; + size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; + size_t const streamingSize = inBuffSize + outBuffSize; - return CCtxSize + streamingSize; + return CCtxSize + streamingSize; + } } size_t ZSTD_estimateCStreamSize_advanced(ZSTD_compressionParameters cParams) diff --git a/lib/zstd.h b/lib/zstd.h index 4cff6974b..03994f9a8 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -498,7 +498,7 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); * It will also consider src size to be arbitrarily "large", which is worst case. * If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced() can provide a tighter estimation. * ZSTD_estimateCCtxSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - * ZSTD_estimateCCtxSize_advanced_opaque() can be used in tandem with ZSTD_CCtxParam_setParameter(). + * ZSTD_estimateCCtxSize_advanced_opaque() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return 0 if ZSTD_p_nbThreads is set to a value > 1. * Note : CCtx estimation is only correct for single-threaded compression */ ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced(ZSTD_compressionParameters cParams); @@ -510,7 +510,7 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); * It will also consider src size to be arbitrarily "large", which is worst case. * If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced() can provide a tighter estimation. * ZSTD_estimateCStreamSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - * ZSTD_estimateCStreamSize_advanced_opaque() can be used in tandem with ZSTD_CCtxParam_setParameter(). + * ZSTD_estimateCStreamSize_advanced_opaque() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return 0 if ZSTD_p_nbThreads is set to a value > 1. * Note : CStream estimation is only correct for single-threaded compression. * ZSTD_DStream memory budget depends on window Size. * This information can be passed manually, using ZSTD_estimateDStreamSize, @@ -1113,7 +1113,8 @@ size_t ZSTD_compress_generic_simpleArgs ( * - ZSTD_compress_generic() : Do compression using the CCtx. * - ZSTD_freeCCtxParams() : Free the memory. * - * This can be used with ZSTD_estimateCCtxSize_opaque() for static allocation. */ + * This can be used with ZSTD_estimateCCtxSize_opaque() for static allocation + * for single-threaded compression. */ ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); diff --git a/tests/Makefile b/tests/Makefile index 3734f7737..006059b72 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -323,6 +323,7 @@ test-zstream: zstreamtest $(QEMU_SYS) ./zstreamtest $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) $(QEMU_SYS) ./zstreamtest --mt $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) $(QEMU_SYS) ./zstreamtest --newapi $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) + $(QEMU_SYS) ./zstreamtest --opaqueapi $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) test-zstream32: zstreamtest32 $(QEMU_SYS) ./zstreamtest32 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) From 89dc856caee4a9c10740b6ee8b20aaa74f1a2b7b Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 24 Aug 2017 16:48:32 -0700 Subject: [PATCH 047/248] [pool] Fix formatting --- lib/common/pool.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/common/pool.c b/lib/common/pool.c index a227044f7..0f848901a 100644 --- a/lib/common/pool.c +++ b/lib/common/pool.c @@ -25,8 +25,8 @@ /* A job is a function and an opaque argument */ typedef struct POOL_job_s { - POOL_function function; - void *opaque; + POOL_function function; + void *opaque; } POOL_job; struct POOL_ctx_s { @@ -214,13 +214,13 @@ void POOL_add(void* ctxVoid, POOL_function function, void *opaque) { /* We don't need any data, but if it is empty malloc() might return NULL. */ struct POOL_ctx_s { - int data; + int data; }; POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { - (void)numThreads; - (void)queueSize; - return (POOL_ctx*)malloc(sizeof(POOL_ctx)); + (void)numThreads; + (void)queueSize; + return (POOL_ctx*)malloc(sizeof(POOL_ctx)); } void POOL_free(POOL_ctx* ctx) { @@ -228,8 +228,8 @@ void POOL_free(POOL_ctx* ctx) { } void POOL_add(void* ctx, POOL_function function, void* opaque) { - (void)ctx; - function(opaque); + (void)ctx; + function(opaque); } size_t POOL_sizeof(POOL_ctx* ctx) { From 26dc040a7b0b527a65da93020a8f4c15652e17ee Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 24 Aug 2017 17:01:41 -0700 Subject: [PATCH 048/248] [pool] Accept custom allocators --- lib/common/pool.c | 32 ++++++++++++++++++++++---------- lib/common/pool.h | 3 +++ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/lib/common/pool.c b/lib/common/pool.c index 0f848901a..ada9b1696 100644 --- a/lib/common/pool.c +++ b/lib/common/pool.c @@ -30,6 +30,7 @@ typedef struct POOL_job_s { } POOL_job; struct POOL_ctx_s { + ZSTD_customMem customMem; /* Keep track of the threads */ pthread_t *threads; size_t numThreads; @@ -98,11 +99,15 @@ static void* POOL_thread(void* opaque) { } POOL_ctx *POOL_create(size_t numThreads, size_t queueSize) { + return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); +} + +POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) { POOL_ctx *ctx; /* Check the parameters */ if (!numThreads) { return NULL; } /* Allocate the context and zero initialize */ - ctx = (POOL_ctx *)calloc(1, sizeof(POOL_ctx)); + ctx = (POOL_ctx *)ZSTD_calloc(sizeof(POOL_ctx), customMem); if (!ctx) { return NULL; } /* Initialize the job queue. * It needs one extra space since one space is wasted to differentiate empty @@ -119,8 +124,9 @@ POOL_ctx *POOL_create(size_t numThreads, size_t queueSize) { (void)pthread_cond_init(&ctx->queuePopCond, NULL); ctx->shutdown = 0; /* Allocate space for the thread handles */ - ctx->threads = (pthread_t*)malloc(numThreads * sizeof(pthread_t)); + ctx->threads = (pthread_t*)ZSTD_malloc(numThreads * sizeof(pthread_t), customMem); ctx->numThreads = 0; + ctx->customMem = customMem; /* Check for errors */ if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; } /* Initialize the threads */ @@ -160,9 +166,9 @@ void POOL_free(POOL_ctx *ctx) { pthread_mutex_destroy(&ctx->queueMutex); pthread_cond_destroy(&ctx->queuePushCond); pthread_cond_destroy(&ctx->queuePopCond); - if (ctx->queue) free(ctx->queue); - if (ctx->threads) free(ctx->threads); - free(ctx); + ZSTD_free(ctx->queue, ctx->customMem); + ZSTD_free(ctx->threads, ctx->customMem); + ZSTD_free(ctx, ctx->customMem); } size_t POOL_sizeof(POOL_ctx *ctx) { @@ -213,18 +219,23 @@ void POOL_add(void* ctxVoid, POOL_function function, void *opaque) { /* No multi-threading support */ /* We don't need any data, but if it is empty malloc() might return NULL. */ -struct POOL_ctx_s { - int data; -}; +struct POOL_ctx_s {}; +static POOL_ctx g_ctx; POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { + return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); +} + +POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) { (void)numThreads; (void)queueSize; - return (POOL_ctx*)malloc(sizeof(POOL_ctx)); + (void)customMem; + return &g_ctx; } void POOL_free(POOL_ctx* ctx) { - free(ctx); + assert(ctx == &g_ctx); + (void)ctx; } void POOL_add(void* ctx, POOL_function function, void* opaque) { @@ -234,6 +245,7 @@ void POOL_add(void* ctx, POOL_function function, void* opaque) { size_t POOL_sizeof(POOL_ctx* ctx) { if (ctx==NULL) return 0; /* supports sizeof NULL */ + assert(ctx == &g_ctx); return sizeof(*ctx); } diff --git a/lib/common/pool.h b/lib/common/pool.h index 264c5c9ca..411b73e11 100644 --- a/lib/common/pool.h +++ b/lib/common/pool.h @@ -16,6 +16,7 @@ extern "C" { #include /* size_t */ +#include "zstd_internal.h" /* ZSTD_customMem */ typedef struct POOL_ctx_s POOL_ctx; @@ -27,6 +28,8 @@ typedef struct POOL_ctx_s POOL_ctx; */ POOL_ctx *POOL_create(size_t numThreads, size_t queueSize); +POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem); + /*! POOL_free() : Free a thread pool returned by POOL_create(). */ From de6c6bce859193ac7dc50a96b01c6de4ae9e328b Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 24 Aug 2017 18:09:50 -0700 Subject: [PATCH 049/248] Fix zstd_internal.h for C++ mode --- lib/common/zstd_common.c | 3 +-- lib/common/zstd_internal.h | 8 ++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/common/zstd_common.c b/lib/common/zstd_common.c index 08384cabf..1155c60c4 100644 --- a/lib/common/zstd_common.c +++ b/lib/common/zstd_common.c @@ -15,8 +15,7 @@ #include /* malloc, calloc, free */ #include /* memset */ #include "error_private.h" -#define ZSTD_STATIC_LINKING_ONLY -#include "zstd.h" +#include "zstd_internal.h" /*-**************************************** diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index ac1f39896..fce75723a 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -29,6 +29,11 @@ #include "xxhash.h" /* XXH_reset, update, digest */ +#if defined (__cplusplus) +extern "C" { +#endif + + /*-************************************* * Debug ***************************************/ @@ -334,5 +339,8 @@ typedef struct { size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr); +#if defined (__cplusplus) +} +#endif #endif /* ZSTD_CCOMMON_H_MODULE */ From db3f5372dfc636c848f8ad5b74c392272b48b326 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 24 Aug 2017 18:12:28 -0700 Subject: [PATCH 050/248] [zstdmt] Use POOL_create_advanced() --- lib/compress/zstdmt_compress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 8564bc439..84a568890 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -426,7 +426,7 @@ ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem) mtctx->allJobsCompleted = 1; mtctx->sectionSize = 0; mtctx->overlapLog = ZSTDMT_OVERLAPLOG_DEFAULT; - mtctx->factory = POOL_create(nbThreads, 0); + mtctx->factory = POOL_create_advanced(nbThreads, 0, cMem); mtctx->jobs = ZSTDMT_allocJobsTable(&nbJobs, cMem); mtctx->jobIDMask = nbJobs - 1; mtctx->bufPool = ZSTDMT_createBufferPool(nbThreads, cMem); From eb7bbab36a1a5b81be860234cd6ec602184d4fc7 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 25 Aug 2017 10:48:07 -0700 Subject: [PATCH 051/248] Remove ZSTD_p_refDictContent and dictContentByRef --- lib/common/zstd_internal.h | 1 - lib/compress/zstd_compress.c | 26 ++++++++++++++++---------- lib/compress/zstdmt_compress.c | 2 +- lib/zstd.h | 13 +++++++++---- tests/zstreamtest.c | 7 +++++-- 5 files changed, 31 insertions(+), 18 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 4e2403bee..393a17247 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -294,7 +294,6 @@ struct ZSTD_CCtx_params_s { U32 forceWindow; /* force back-references to respect limit of * 1<requestedParams, param, value); case ZSTD_p_dictMode: - case ZSTD_p_refDictContent: if (cctx->cdict) return ERROR(stage_wrong); /* must be set before loading */ return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); @@ -463,11 +462,6 @@ size_t ZSTD_CCtxParam_setParameter( params->dictMode = (ZSTD_dictMode_e)value; return 0; - case ZSTD_p_refDictContent : - /* dictionary content will be referenced, instead of copied */ - params->dictContentByRef = value > 0; - return 0; - case ZSTD_p_forceMaxWindow : params->forceWindow = value > 0; return 0; @@ -514,7 +508,6 @@ size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params /* Assume dictionary parameters are validated */ cctx->requestedParams.dictMode = params->dictMode; - cctx->requestedParams.dictContentByRef = params->dictContentByRef; /* Set force window explicitly since it sets cctx->loadedDictEnd */ CHECK_F( ZSTD_CCtx_setParameter( @@ -541,7 +534,8 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo return 0; } -ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) +size_t ZSTD_CCtx_loadDictionary_internal( + ZSTD_CCtx* cctx, const void* dict, size_t dictSize, unsigned byReference) { if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */ @@ -557,7 +551,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, s ZSTD_getCParams(cctx->requestedParams.compressionLevel, 0, dictSize); cctx->cdictLocal = ZSTD_createCDict_advanced( dict, dictSize, - cctx->requestedParams.dictContentByRef, + byReference, cctx->requestedParams.dictMode, cParams, cctx->customMem); cctx->cdict = cctx->cdictLocal; @@ -567,6 +561,18 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, s return 0; } +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference( + ZSTD_CCtx* cctx, const void* dict, size_t dictSize) +{ + return ZSTD_CCtx_loadDictionary_internal(cctx, dict, dictSize, 1); +} + +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) +{ + return ZSTD_CCtx_loadDictionary_internal(cctx, dict, dictSize, 0); +} + + size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) { if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); @@ -3896,7 +3902,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, ZSTD_freeCDict(zcs->cdictLocal); zcs->cdictLocal = ZSTD_createCDict_advanced( dict, dictSize, - params.dictContentByRef, params.dictMode, + 0 /* byReference */, params.dictMode, params.cParams, zcs->customMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index f7f02cfbb..fae17e656 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -344,7 +344,7 @@ void ZSTDMT_compressChunk(void* jobDescription) { ZSTD_CCtx_params jobParams = job->params; /* Force loading dictionary in "content-only" mode (no header analysis) */ size_t const dictModeError = - ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_dictMode, 1); + ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_dictMode, (U32)ZSTD_dm_rawContent); size_t const forceWindowError = ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk); /* Note: ZSTD_setCCtxParameter() should not be used here. diff --git a/lib/zstd.h b/lib/zstd.h index 03994f9a8..01fbb18cd 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -970,8 +970,6 @@ typedef enum { /* dictionary parameters (must be set before ZSTD_CCtx_loadDictionary) */ ZSTD_p_dictMode=300, /* Select how dictionary content must be interpreted. Value must be from type ZSTD_dictMode_e. * default : 0==auto : dictionary will be "full" if it respects specification, otherwise it will be "rawContent" */ - ZSTD_p_refDictContent, /* Dictionary content will be referenced, instead of copied (default:0==byCopy). - * It requires that dictionary buffer outlives its users */ /* multi-threading parameters */ ZSTD_p_nbThreads=400, /* Select how many threads a compression job can spawn (default:1) @@ -1015,8 +1013,9 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo * @result : 0, or an error code (which can be tested with ZSTD_isError()). * Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary, * meaning "return to no-dictionary mode". - * Note 1 : `dict` content will be copied internally, - * except if ZSTD_p_refDictContent is set before loading. + * Note 1 : `dict` content will be copied internally. Use + * ZSTD_CCtx_loadDictionary_byReference() to reference dictionary + * content instead. * Note 2 : Loading a dictionary involves building tables, which are dependent on compression parameters. * For this reason, compression parameters cannot be changed anymore after loading a dictionary. * It's also a CPU-heavy operation, with non-negligible impact on latency. @@ -1024,6 +1023,12 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo * To return to "no-dictionary" situation, load a NULL dictionary */ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); +/*! ZSTD_CCtx_loadDictionary_byReference() : + * Same as ZSTD_CCtx_loadDictionary() except dictionary content will be + * referenced, instead of copied. The dictionary buffer must outlive its users. + */ +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); + /*! ZSTD_CCtx_refCDict() : * Reference a prepared dictionary, to be used for all next compression jobs. * Note that compression parameters are enforced from within CDict, diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 98e121949..0373676d0 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1366,7 +1366,6 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) ); DISPLAYLEVEL(5, "pledgedSrcSize : %u \n", (U32)pledgedSrcSize); - if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_refDictContent, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); /* multi-threading parameters */ { U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1; U32 const nbThreads = MIN(nbThreadsCandidate, nbThreadsMax); @@ -1386,7 +1385,11 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double } if (FUZ_rand(&lseed) & 1) { - CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) ); + if (FUZ_rand(&lseed) & 1) { + CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) ); + } else { + CHECK_Z( ZSTD_CCtx_loadDictionary_byReference(zc, dict, dictSize) ); + } if (dict && dictSize) { /* test that compression parameters are rejected (correctly) after loading a non-NULL dictionary */ if (useOpaqueAPI) { From de5193422d458be51531cd429d1d9b5cd5d78a92 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 25 Aug 2017 11:36:17 -0700 Subject: [PATCH 052/248] Distinguish between jobParams and cctxParams in zstdmt --- lib/compress/zstdmt_compress.c | 36 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index fae17e656..cf21177e0 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -556,10 +556,10 @@ static size_t ZSTDMT_compress_advanced_internal( ZSTD_CCtx_params const cctxParams, unsigned overlapLog) { - ZSTD_CCtx_params const requestedParams = ZSTDMT_makeJobCCtxParams(cctxParams); + ZSTD_CCtx_params const jobParams = ZSTDMT_makeJobCCtxParams(cctxParams); unsigned const overlapRLog = (overlapLog>9) ? 0 : 9-overlapLog; - size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (requestedParams.cParams.windowLog - overlapRLog); - unsigned nbChunks = computeNbChunks(srcSize, requestedParams.cParams.windowLog, mtctx->nbThreads); + size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (cctxParams.cParams.windowLog - overlapRLog); + unsigned nbChunks = computeNbChunks(srcSize, cctxParams.cParams.windowLog, mtctx->nbThreads); size_t const proposedChunkSize = (srcSize + (nbChunks-1)) / nbChunks; size_t const avgChunkSize = ((proposedChunkSize & 0x1FFFF) < 0x7FFF) ? proposedChunkSize + 0xFFFF : proposedChunkSize; /* avoid too small last block */ const char* const srcStart = (const char*)src; @@ -571,8 +571,8 @@ static size_t ZSTDMT_compress_advanced_internal( DEBUGLOG(4, "nbChunks : %2u (chunkSize : %u bytes) ", nbChunks, (U32)avgChunkSize); if (nbChunks==1) { /* fallback to single-thread mode */ ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0]; - if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, requestedParams.fParams); - return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, NULL, 0, requestedParams); + if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, jobParams.fParams); + return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, NULL, 0, jobParams); } assert(avgChunkSize >= 256 KB); /* condition for ZSTD_compressBound(A) + ZSTD_compressBound(B) <= ZSTD_compressBound(A+B), which is required for compressWithinDst */ ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(avgChunkSize) ); @@ -601,7 +601,7 @@ static size_t ZSTDMT_compress_advanced_internal( mtctx->jobs[u].srcSize = chunkSize; mtctx->jobs[u].cdict = mtctx->nextJobID==0 ? cdict : NULL; mtctx->jobs[u].fullFrameSize = srcSize; - mtctx->jobs[u].params = requestedParams; + mtctx->jobs[u].params = jobParams; /* do not calculate checksum within sections, but write it in header for first section */ if (u!=0) mtctx->jobs[u].params.fParams.checksumFlag = 0; mtctx->jobs[u].dstBuff = dstBuffer; @@ -613,7 +613,7 @@ static size_t ZSTDMT_compress_advanced_internal( mtctx->jobs[u].jobCompleted_mutex = &mtctx->jobCompleted_mutex; mtctx->jobs[u].jobCompleted_cond = &mtctx->jobCompleted_cond; - if (requestedParams.fParams.checksumFlag) { + if (cctxParams.fParams.checksumFlag) { XXH64_update(&xxh64, srcStart + frameStartPos, chunkSize); } @@ -656,8 +656,8 @@ static size_t ZSTDMT_compress_advanced_internal( } } /* for (chunkID=0; chunkID dstCapacity) { error = ERROR(dstSize_tooSmall); @@ -725,17 +725,17 @@ size_t ZSTDMT_initCStream_internal( const ZSTD_CDict* cdict, ZSTD_CCtx_params cctxParams, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params const requestedParams = ZSTDMT_makeJobCCtxParams(cctxParams); DEBUGLOG(4, "ZSTDMT_initCStream_internal"); /* params are supposed to be fully validated at this point */ - assert(!ZSTD_isError(ZSTD_checkCParams(requestedParams.cParams))); + assert(!ZSTD_isError(ZSTD_checkCParams(cctxParams.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ if (zcs->nbThreads==1) { + ZSTD_CCtx_params const jobParams = ZSTDMT_makeJobCCtxParams(cctxParams); DEBUGLOG(4, "single thread mode"); return ZSTD_initCStream_internal(zcs->cctxPool->cctx[0], dict, dictSize, cdict, - requestedParams, pledgedSrcSize); + jobParams, pledgedSrcSize); } if (zcs->allJobsCompleted == 0) { /* previous compression not correctly finished */ @@ -744,14 +744,14 @@ size_t ZSTDMT_initCStream_internal( zcs->allJobsCompleted = 1; } - zcs->params = requestedParams; + zcs->params = cctxParams; zcs->frameContentSize = pledgedSrcSize; if (dict) { DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal); ZSTD_freeCDict(zcs->cdictLocal); zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0 /* byRef */, ZSTD_dm_auto, /* note : a loadPrefix becomes an internal CDict */ - requestedParams.cParams, zcs->cMem); + cctxParams.cParams, zcs->cMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); } else { @@ -776,7 +776,7 @@ size_t ZSTDMT_initCStream_internal( zcs->nextJobID = 0; zcs->frameEnded = 0; zcs->allJobsCompleted = 0; - if (requestedParams.fParams.checksumFlag) XXH64_reset(&zcs->xxhState, 0); + if (cctxParams.fParams.checksumFlag) XXH64_reset(&zcs->xxhState, 0); return 0; } @@ -798,11 +798,11 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params requestedParams = ZSTD_getCCtxParamsFromCDict(cdict); + ZSTD_CCtx_params params = ZSTD_getCCtxParamsFromCDict(cdict); if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */ - requestedParams.fParams = fParams; + params.fParams = fParams; return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, cdict, - requestedParams, pledgedSrcSize); + params, pledgedSrcSize); } From 991115372341f7c7d28d81304b0dbae6c30d2ba9 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 25 Aug 2017 13:14:51 -0700 Subject: [PATCH 053/248] Move jobSize and overlapLog in zstdmt to cctxParams --- lib/compress/zstd_compress.c | 23 ++++---- lib/compress/zstdmt_compress.c | 100 ++++++++++++++++++++------------- tests/Makefile | 2 +- tests/roundTripCrash.c | 3 + 4 files changed, 77 insertions(+), 51 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 5c7a724cc..c87037196 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -307,6 +307,10 @@ static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( return ERROR(parameter_outOfBound); \ } } +size_t ZSTDMT_CCtxParam_setMTCtxParameter( + ZSTD_CCtx_params* params, ZSDTMT_parameter parameter, unsigned value); +size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads); + size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value) { if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); @@ -359,19 +363,20 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v cctx->mtctx = ZSTDMT_createCCtx_advanced(value, cctx->customMem); if (cctx->mtctx == NULL) return ERROR(memory_allocation); } - cctx->requestedParams.nbThreads = value; - return 0; + + /* Need to initialize overlapSizeLog */ + return ZSTDMT_initializeCCtxParameters(&cctx->requestedParams, value); case ZSTD_p_jobSize: if (cctx->requestedParams.nbThreads <= 1) return ERROR(parameter_unsupported); assert(cctx->mtctx != NULL); - return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_sectionSize, value); + return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); case ZSTD_p_overlapSizeLog: DEBUGLOG(5, " setting overlap with nbThreads == %u", cctx->requestedParams.nbThreads); if (cctx->requestedParams.nbThreads <= 1) return ERROR(parameter_unsupported); assert(cctx->mtctx != NULL); - return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_overlapSectionLog, value); + return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); default: return ERROR(parameter_unsupported); } @@ -471,19 +476,15 @@ size_t ZSTD_CCtxParam_setParameter( #ifndef ZSTD_MULTITHREAD if (value > 1) return ERROR(parameter_unsupported); #endif - /* Do checks when applying params to cctx */ - params->nbThreads = value; - return 0; + return ZSTDMT_initializeCCtxParameters(params, value); case ZSTD_p_jobSize : if (params->nbThreads <= 1) return ERROR(parameter_unsupported); - params->jobSize = value; - return 0; + return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_sectionSize, value); case ZSTD_p_overlapSizeLog : if (params->nbThreads <= 1) return ERROR(parameter_unsupported); - params->overlapSizeLog = value; - return 0; + return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_overlapSectionLog, value); default: return ERROR(parameter_unsupported); } diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index cf21177e0..7c3bd0198 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -404,15 +404,12 @@ struct ZSTDMT_CCtx_s { inBuff_t inBuff; ZSTD_CCtx_params params; XXH64_state_t xxhState; - unsigned nbThreads; unsigned jobIDMask; unsigned doneJobID; unsigned nextJobID; unsigned frameEnded; unsigned allJobsCompleted; - unsigned overlapLog; unsigned long long frameContentSize; - size_t sectionSize; ZSTD_customMem cMem; ZSTD_CDict* cdictLocal; const ZSTD_CDict* cdict; @@ -427,6 +424,15 @@ static ZSTDMT_jobDescription* ZSTDMT_allocJobsTable(U32* nbJobsPtr, ZSTD_customM nbJobs * sizeof(ZSTDMT_jobDescription), cMem); } +/* Internal only */ +size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads) +{ + params->nbThreads = nbThreads; + params->overlapSizeLog = ZSTDMT_OVERLAPLOG_DEFAULT; + params->jobSize = 0; + return 0; +} + ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem) { ZSTDMT_CCtx* mtctx; @@ -441,11 +447,9 @@ ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem) mtctx = (ZSTDMT_CCtx*) ZSTD_calloc(sizeof(ZSTDMT_CCtx), cMem); if (!mtctx) return NULL; + ZSTDMT_initializeCCtxParameters(&mtctx->params, nbThreads); mtctx->cMem = cMem; - mtctx->nbThreads = nbThreads; mtctx->allJobsCompleted = 1; - mtctx->sectionSize = 0; - mtctx->overlapLog = ZSTDMT_OVERLAPLOG_DEFAULT; mtctx->factory = POOL_create(nbThreads, 1); mtctx->jobs = ZSTDMT_allocJobsTable(&nbJobs, cMem); mtctx->jobIDMask = nbJobs - 1; @@ -516,22 +520,35 @@ size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx) + ZSTD_sizeof_CDict(mtctx->cdictLocal); } -size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSDTMT_parameter parameter, unsigned value) -{ +/* Internal only */ +size_t ZSTDMT_CCtxParam_setMTCtxParameter( + ZSTD_CCtx_params* params, ZSDTMT_parameter parameter, unsigned value) { switch(parameter) { case ZSTDMT_p_sectionSize : - mtctx->sectionSize = value; + params->jobSize = value; return 0; case ZSTDMT_p_overlapSectionLog : DEBUGLOG(5, "ZSTDMT_p_overlapSectionLog : %u", value); - mtctx->overlapLog = (value >= 9) ? 9 : value; + params->overlapSizeLog = (value >= 9) ? 9 : value; return 0; default : return ERROR(parameter_unsupported); } } +size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSDTMT_parameter parameter, unsigned value) +{ + switch(parameter) + { + case ZSTDMT_p_sectionSize : + return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value); + case ZSTDMT_p_overlapSectionLog : + return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value); + default : + return ERROR(parameter_unsupported); + } +} /* ------------------------------------------ */ /* ===== Multi-threaded compression ===== */ @@ -553,13 +570,12 @@ static size_t ZSTDMT_compress_advanced_internal( void* dst, size_t dstCapacity, const void* src, size_t srcSize, const ZSTD_CDict* cdict, - ZSTD_CCtx_params const cctxParams, - unsigned overlapLog) + ZSTD_CCtx_params const params) { - ZSTD_CCtx_params const jobParams = ZSTDMT_makeJobCCtxParams(cctxParams); - unsigned const overlapRLog = (overlapLog>9) ? 0 : 9-overlapLog; - size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (cctxParams.cParams.windowLog - overlapRLog); - unsigned nbChunks = computeNbChunks(srcSize, cctxParams.cParams.windowLog, mtctx->nbThreads); + ZSTD_CCtx_params const jobParams = ZSTDMT_makeJobCCtxParams(params); + unsigned const overlapRLog = (params.overlapSizeLog>9) ? 0 : 9-params.overlapSizeLog; + size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (params.cParams.windowLog - overlapRLog); + unsigned nbChunks = computeNbChunks(srcSize, params.cParams.windowLog, params.nbThreads); size_t const proposedChunkSize = (srcSize + (nbChunks-1)) / nbChunks; size_t const avgChunkSize = ((proposedChunkSize & 0x1FFFF) < 0x7FFF) ? proposedChunkSize + 0xFFFF : proposedChunkSize; /* avoid too small last block */ const char* const srcStart = (const char*)src; @@ -567,6 +583,8 @@ static size_t ZSTDMT_compress_advanced_internal( unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbChunks : (unsigned)(dstCapacity / ZSTD_compressBound(avgChunkSize)); /* presumes avgChunkSize >= 256 KB, which should be the case */ size_t frameStartPos = 0, dstBufferPos = 0; XXH64_state_t xxh64; + assert(jobParams.nbThreads == 0); + assert(mtctx->cctxPool.totalCCtx == params.nbThreads); DEBUGLOG(4, "nbChunks : %2u (chunkSize : %u bytes) ", nbChunks, (U32)avgChunkSize); if (nbChunks==1) { /* fallback to single-thread mode */ @@ -613,7 +631,7 @@ static size_t ZSTDMT_compress_advanced_internal( mtctx->jobs[u].jobCompleted_mutex = &mtctx->jobCompleted_mutex; mtctx->jobs[u].jobCompleted_cond = &mtctx->jobCompleted_cond; - if (cctxParams.fParams.checksumFlag) { + if (params.fParams.checksumFlag) { XXH64_update(&xxh64, srcStart + frameStartPos, chunkSize); } @@ -656,8 +674,8 @@ static size_t ZSTDMT_compress_advanced_internal( } } /* for (chunkID=0; chunkID dstCapacity) { error = ERROR(dstSize_tooSmall); @@ -682,10 +700,11 @@ size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, ZSTD_CCtx_params cctxParams = mtctx->params; cctxParams.cParams = params.cParams; cctxParams.fParams = params.fParams; + cctxParams.overlapSizeLog = overlapLog; return ZSTDMT_compress_advanced_internal(mtctx, dst, dstCapacity, src, srcSize, - cdict, cctxParams, overlapLog); + cdict, cctxParams); } @@ -722,20 +741,22 @@ static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs) size_t ZSTDMT_initCStream_internal( ZSTDMT_CCtx* zcs, const void* dict, size_t dictSize, - const ZSTD_CDict* cdict, ZSTD_CCtx_params cctxParams, + const ZSTD_CDict* cdict, ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) { DEBUGLOG(4, "ZSTDMT_initCStream_internal"); /* params are supposed to be fully validated at this point */ - assert(!ZSTD_isError(ZSTD_checkCParams(cctxParams.cParams))); + assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ + assert(mtctx->cctxPool.totalCCtx == params.nbThreads); - if (zcs->nbThreads==1) { - ZSTD_CCtx_params const jobParams = ZSTDMT_makeJobCCtxParams(cctxParams); + if (params.nbThreads==1) { + ZSTD_CCtx_params const singleThreadParams = ZSTDMT_makeJobCCtxParams(params); DEBUGLOG(4, "single thread mode"); + assert(singleThreadParams.nbThreads == 0); return ZSTD_initCStream_internal(zcs->cctxPool->cctx[0], dict, dictSize, cdict, - jobParams, pledgedSrcSize); + singleThreadParams, pledgedSrcSize); } if (zcs->allJobsCompleted == 0) { /* previous compression not correctly finished */ @@ -744,14 +765,14 @@ size_t ZSTDMT_initCStream_internal( zcs->allJobsCompleted = 1; } - zcs->params = cctxParams; + zcs->params = params; zcs->frameContentSize = pledgedSrcSize; if (dict) { DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal); ZSTD_freeCDict(zcs->cdictLocal); zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0 /* byRef */, ZSTD_dm_auto, /* note : a loadPrefix becomes an internal CDict */ - cctxParams.cParams, zcs->cMem); + params.cParams, zcs->cMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); } else { @@ -761,10 +782,10 @@ size_t ZSTDMT_initCStream_internal( zcs->cdict = cdict; } - zcs->targetDictSize = (zcs->overlapLog==0) ? 0 : (size_t)1 << (zcs->params.cParams.windowLog - (9 - zcs->overlapLog)); - DEBUGLOG(4, "overlapLog : %u ", zcs->overlapLog); + zcs->targetDictSize = (params.overlapSizeLog==0) ? 0 : (size_t)1 << (params.cParams.windowLog - (9 - params.overlapSizeLog)); + DEBUGLOG(4, "overlapLog : %u ", params.overlapSizeLog); DEBUGLOG(4, "overlap Size : %u KB", (U32)(zcs->targetDictSize>>10)); - zcs->targetSectionSize = zcs->sectionSize ? zcs->sectionSize : (size_t)1 << (zcs->params.cParams.windowLog + 2); + zcs->targetSectionSize = params.jobSize ? params.jobSize : (size_t)1 << (params.cParams.windowLog + 2); zcs->targetSectionSize = MAX(ZSTDMT_SECTION_SIZE_MIN, zcs->targetSectionSize); zcs->targetSectionSize = MAX(zcs->targetDictSize, zcs->targetSectionSize); DEBUGLOG(4, "Section Size : %u KB", (U32)(zcs->targetSectionSize>>10)); @@ -776,7 +797,7 @@ size_t ZSTDMT_initCStream_internal( zcs->nextJobID = 0; zcs->frameEnded = 0; zcs->allJobsCompleted = 0; - if (cctxParams.fParams.checksumFlag) XXH64_reset(&zcs->xxhState, 0); + if (params.fParams.checksumFlag) XXH64_reset(&zcs->xxhState, 0); return 0; } @@ -798,11 +819,12 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params params = ZSTD_getCCtxParamsFromCDict(cdict); + ZSTD_CCtx_params cctxParams = mtctx->params; + cctxParams.cParams = ZSTD_getCCtxParamsFromCDict(cdict).cParams; + cctxParams.fParams = fParams; if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */ - params.fParams = fParams; return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, cdict, - params, pledgedSrcSize); + cctxParams, pledgedSrcSize); } @@ -810,7 +832,7 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, * pledgedSrcSize is optional and can be zero == unknown */ size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* zcs, unsigned long long pledgedSrcSize) { - if (zcs->nbThreads==1) + if (zcs->params.nbThreads==1) return ZSTD_resetCStream(zcs->cctxPool->cctx[0], pledgedSrcSize); return ZSTDMT_initCStream_internal(zcs, NULL, 0, 0, zcs->params, pledgedSrcSize); @@ -965,7 +987,7 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, /* current frame being ended. Only flush/end are allowed. Or start new frame with init */ return ERROR(stage_wrong); } - if (mtctx->nbThreads==1) { /* delegate to single-thread (synchronous) */ + if (mtctx->params.nbThreads==1) { /* delegate to single-thread (synchronous) */ return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp); } @@ -977,7 +999,7 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, size_t const cSize = ZSTDMT_compress_advanced_internal(mtctx, (char*)output->dst + output->pos, output->size - output->pos, (const char*)input->src + input->pos, input->size - input->pos, - mtctx->cdict, mtctx->params, mtctx->overlapLog); + mtctx->cdict, mtctx->params); if (ZSTD_isError(cSize)) return cSize; input->pos = input->size; output->pos += cSize; @@ -1052,7 +1074,7 @@ static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* outp size_t ZSTDMT_flushStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output) { DEBUGLOG(5, "ZSTDMT_flushStream"); - if (zcs->nbThreads==1) + if (zcs->params.nbThreads==1) return ZSTD_flushStream(zcs->cctxPool->cctx[0], output); return ZSTDMT_flushStream_internal(zcs, output, 0 /* endFrame */); } @@ -1060,7 +1082,7 @@ size_t ZSTDMT_flushStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output) size_t ZSTDMT_endStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output) { DEBUGLOG(4, "ZSTDMT_endStream"); - if (zcs->nbThreads==1) + if (zcs->params.nbThreads==1) return ZSTD_endStream(zcs->cctxPool->cctx[0], output); return ZSTDMT_flushStream_internal(zcs, output, 1 /* endFrame */); } diff --git a/tests/Makefile b/tests/Makefile index 006059b72..f6389bd91 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -167,7 +167,7 @@ datagen : $(PRGDIR)/datagen.c datagencli.c $(CC) $(FLAGS) $^ -o $@$(EXT) roundTripCrash : $(ZSTD_FILES) roundTripCrash.c - $(CC) $(FLAGS) $^ -o $@$(EXT) + $(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT) longmatch : $(ZSTD_FILES) longmatch.c $(CC) $(FLAGS) $^ -o $@$(EXT) diff --git a/tests/roundTripCrash.c b/tests/roundTripCrash.c index fb14fa87b..cb0221c58 100644 --- a/tests/roundTripCrash.c +++ b/tests/roundTripCrash.c @@ -93,6 +93,9 @@ static size_t cctxParamRoundTripTest(void* resultBuff, size_t resultBuffCapacity /* Set parameters */ CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_compressionLevel, cLevel) ); + CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_nbThreads, 2) ); + CHECK_Z( ZSTD_CCtxParam_setParameter(cctxParams, ZSTD_p_overlapSizeLog, 5) ); + /* Apply parameters */ CHECK_Z( ZSTD_CCtx_applyCCtxParams(cctx, cctxParams) ); From 0744592d385df6718f46b7e7d8201609e0459a40 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 25 Aug 2017 13:23:16 -0700 Subject: [PATCH 054/248] Add function initializing cctxParams from clevel --- lib/compress/zstd_compress.c | 7 ++++++- lib/compress/zstdmt_compress.c | 4 ++-- lib/zstd.h | 11 ++++++++--- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index c87037196..c8cfd6c94 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -282,7 +282,12 @@ size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params) return 0; } -size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) +size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, int compressionLevel) { + ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0); + return ZSTD_initCCtxParams_advanced(cctxParams, params); +} + +size_t ZSTD_initCCtxParams_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) { if (!cctxParams) { return ERROR(GENERIC); } CHECK_F( ZSTD_checkCParams(params.cParams) ); diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 7c3bd0198..c93d784da 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -584,7 +584,7 @@ static size_t ZSTDMT_compress_advanced_internal( size_t frameStartPos = 0, dstBufferPos = 0; XXH64_state_t xxh64; assert(jobParams.nbThreads == 0); - assert(mtctx->cctxPool.totalCCtx == params.nbThreads); + assert(mtctx->cctxPool->totalCCtx == params.nbThreads); DEBUGLOG(4, "nbChunks : %2u (chunkSize : %u bytes) ", nbChunks, (U32)avgChunkSize); if (nbChunks==1) { /* fallback to single-thread mode */ @@ -748,7 +748,7 @@ size_t ZSTDMT_initCStream_internal( /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ - assert(mtctx->cctxPool.totalCCtx == params.nbThreads); + assert(zcs->cctxPool->totalCCtx == params.nbThreads); if (params.nbThreads==1) { ZSTD_CCtx_params const singleThreadParams = ZSTDMT_makeJobCCtxParams(params); diff --git a/lib/zstd.h b/lib/zstd.h index 01fbb18cd..bfbe82849 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -1128,9 +1128,14 @@ ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); ZSTDLIB_API size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params); /*! ZSTD_initCCtxParams() : - * Set the compression and frame parameters of cctxParams according to params. - * All other parameters are reset to their default values. */ -ZSTDLIB_API size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); + * Initializes the compression parameters of cctxParams according to + * compression level. All other parameters are reset to their default values. */ +ZSTDLIB_API size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, int compressionLevel); + +/*! ZSTD_initCCtxParams_advanced() : + * Initializes the compression and frame parameters of cctxParams according to + * params. All other parameters are reset to their default values. */ +ZSTDLIB_API size_t ZSTD_initCCtxParams_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); From 18224608ffa214221b16e55db8759f5486985568 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 25 Aug 2017 13:58:41 -0700 Subject: [PATCH 055/248] Remove ZSTD_setCCtxParameter() --- lib/compress/zstd_compress.c | 22 ---------------------- lib/compress/zstdmt_compress.c | 3 --- lib/zstd.h | 30 ++++++++++++------------------ tests/fuzzer.c | 1 - 4 files changed, 12 insertions(+), 44 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index c8cfd6c94..74cbe53b0 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -197,28 +197,6 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) /* private API call, for dictBuilder only */ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } -/* older variant; will be deprecated */ -/* Both requested and applied params need to be set as this function can be - * called before/after ZSTD_parameters have been applied. */ -size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value) -{ - switch(param) - { - case ZSTD_p_forceWindow : - cctx->requestedParams.forceWindow = value>0; - cctx->appliedParams.forceWindow = value>0; - cctx->loadedDictEnd = 0; - return 0; - ZSTD_STATIC_ASSERT(ZSTD_dm_auto==0); - ZSTD_STATIC_ASSERT(ZSTD_dm_rawContent==1); - case ZSTD_p_forceRawDict : - cctx->requestedParams.dictMode = (ZSTD_dictMode_e)(value>0); - cctx->appliedParams.dictMode = (ZSTD_dictMode_e)(value>0); - return 0; - default: return ERROR(parameter_unsupported); - } -} - #define ZSTD_CLEVEL_CUSTOM 999 static void ZSTD_cLevelToCCtxParams_srcSize(ZSTD_CCtx_params* params, U64 srcSize) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index c93d784da..5f0f254c2 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -347,9 +347,6 @@ void ZSTDMT_compressChunk(void* jobDescription) ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_dictMode, (U32)ZSTD_dm_rawContent); size_t const forceWindowError = ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk); - /* Note: ZSTD_setCCtxParameter() should not be used here. - * ZSTD_compressBegin_advanced_internal() copies the ZSTD_CCtx_params - * directly to appliedParams. */ size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, job->srcStart, job->dictSize, jobParams, job->fullFrameSize); if (ZSTD_isError(initError) || ZSTD_isError(dictModeError) || ZSTD_isError(forceWindowError)) { job->cSize = initError; goto _endJob; } diff --git a/lib/zstd.h b/lib/zstd.h index bfbe82849..0c970f3f9 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -558,17 +558,6 @@ ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); ZSTDLIB_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize); -/* !!! To be deprecated !!! */ -typedef enum { - ZSTD_p_forceWindow, /* Force back-references to remain < windowSize, even when referencing Dictionary content (default:0) */ - ZSTD_p_forceRawDict /* Force loading dictionary in "content-only" mode (no header analysis) */ -} ZSTD_CCtxParameter; -/*! ZSTD_setCCtxParameter() : - * Set advanced parameters, selected through enum ZSTD_CCtxParameter - * @result : 0, or an error code (which can be tested with ZSTD_isError()) */ -ZSTDLIB_API size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value); - - /*! ZSTD_createCDict_byReference() : * Create a digested dictionary for compression * Dictionary content is simply referenced, and therefore stays in dictBuffer. @@ -1119,22 +1108,25 @@ size_t ZSTD_compress_generic_simpleArgs ( * - ZSTD_freeCCtxParams() : Free the memory. * * This can be used with ZSTD_estimateCCtxSize_opaque() for static allocation - * for single-threaded compression. */ - + * for single-threaded compression. + */ ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); /*! ZSTD_resetCCtxParams() : - * Reset params to default, with the default compression level. */ + * Reset params to default, with the default compression level. + */ ZSTDLIB_API size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params); /*! ZSTD_initCCtxParams() : * Initializes the compression parameters of cctxParams according to - * compression level. All other parameters are reset to their default values. */ + * compression level. All other parameters are reset to their default values. + */ ZSTDLIB_API size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, int compressionLevel); /*! ZSTD_initCCtxParams_advanced() : * Initializes the compression and frame parameters of cctxParams according to - * params. All other parameters are reset to their default values. */ + * params. All other parameters are reset to their default values. + */ ZSTDLIB_API size_t ZSTD_initCCtxParams_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); @@ -1144,14 +1136,16 @@ ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); * Set one compression parameter, selected by enum ZSTD_cParameter. * Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_applyCCtxParams(). * Note : when `value` is an enum, cast it to unsigned for proper type checking. - * @result : 0, or an error code (which can be tested with ZSTD_isError()). */ + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + */ ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value); /*! ZSTD_CCtx_applyCCtxParams() : * Apply a set of ZSTD_CCtx_params to the compression context. * This must be done before the dictionary is loaded. * The pledgedSrcSize is treated as unknown. - * Multithreading parameters are applied only if nbThreads > 1. */ + * Multithreading parameters are applied only if nbThreads > 1. + */ ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); /** diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 046c67ea8..3f7595e99 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -1334,7 +1334,6 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD } CHECK_Z( ZSTD_copyCCtx(ctx, refCtx, 0) ); } - ZSTD_setCCtxParameter(ctx, ZSTD_p_forceWindow, FUZ_rand(&lseed) & 1); { U32 const nbChunks = (FUZ_rand(&lseed) & 127) + 2; U32 n; From 2adde898c800e30ec43afef5eec5f5caf7ffc950 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 25 Aug 2017 16:13:40 -0700 Subject: [PATCH 056/248] Fix typo with ZSTDMT_parameter --- lib/common/zstd_internal.h | 2 +- lib/compress/zstd_compress.c | 2 +- lib/compress/zstdmt_compress.c | 4 ++-- lib/compress/zstdmt_compress.h | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 393a17247..53de69739 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -297,7 +297,7 @@ struct ZSTD_CCtx_params_s { ZSTD_dictMode_e dictMode; /* select restricting dictionary to "rawContent" * or "fullDict" only */ - /* Multithreading: used only to set mtctx parameters */ + /* Multithreading: used to pass parameters to mtctx */ U32 nbThreads; unsigned jobSize; unsigned overlapSizeLog; diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 74cbe53b0..6f4121c75 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -291,7 +291,7 @@ static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( } } size_t ZSTDMT_CCtxParam_setMTCtxParameter( - ZSTD_CCtx_params* params, ZSDTMT_parameter parameter, unsigned value); + ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value); size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads); size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 5f0f254c2..8687ea3c0 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -519,7 +519,7 @@ size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx) /* Internal only */ size_t ZSTDMT_CCtxParam_setMTCtxParameter( - ZSTD_CCtx_params* params, ZSDTMT_parameter parameter, unsigned value) { + ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value) { switch(parameter) { case ZSTDMT_p_sectionSize : @@ -534,7 +534,7 @@ size_t ZSTDMT_CCtxParam_setMTCtxParameter( } } -size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSDTMT_parameter parameter, unsigned value) +size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, unsigned value) { switch(parameter) { diff --git a/lib/compress/zstdmt_compress.h b/lib/compress/zstdmt_compress.h index 843a240aa..4381af363 100644 --- a/lib/compress/zstdmt_compress.h +++ b/lib/compress/zstdmt_compress.h @@ -80,19 +80,19 @@ ZSTDLIB_API size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, ZSTD_frameParameters fparams, unsigned long long pledgedSrcSize); /* note : zero means empty */ -/* ZSDTMT_parameter : +/* ZSTDMT_parameter : * List of parameters that can be set using ZSTDMT_setMTCtxParameter() */ typedef enum { ZSTDMT_p_sectionSize, /* size of input "section". Each section is compressed in parallel. 0 means default, which is dynamically determined within compression functions */ ZSTDMT_p_overlapSectionLog /* Log of overlapped section; 0 == no overlap, 6(default) == use 1/8th of window, >=9 == use full window */ -} ZSDTMT_parameter; +} ZSTDMT_parameter; /* ZSTDMT_setMTCtxParameter() : * allow setting individual parameters, one at a time, among a list of enums defined in ZSTDMT_parameter. * The function must be called typically after ZSTD_createCCtx(). * Parameters not explicitly reset by ZSTDMT_init*() remain the same in consecutive compression sessions. * @return : 0, or an error code (which can be tested using ZSTD_isError()) */ -ZSTDLIB_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSDTMT_parameter parameter, unsigned value); +ZSTDLIB_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, unsigned value); /*! ZSTDMT_compressStream_generic() : From 024098a47dba898d60e578cbc93bdc9fca6d8016 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 25 Aug 2017 17:58:28 -0700 Subject: [PATCH 057/248] Fix parameter retrieval from cdict --- lib/common/zstd_internal.h | 4 ++-- lib/compress/zstd_compress.c | 15 ++++++++------- lib/compress/zstdmt_compress.c | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 53de69739..bfec42fad 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -369,9 +369,9 @@ size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, ZSTD_inBuffer* input, ZSTD_EndDirective const flushMode); -/*! ZSTD_getParamsFromCDict() : +/*! ZSTD_getCParamsFromCDict() : * as the name implies */ -ZSTD_CCtx_params ZSTD_getCCtxParamsFromCDict(const ZSTD_CDict* cdict); +ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict); /* INTERNAL */ size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 6f4121c75..1f570a92a 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -477,7 +477,7 @@ size_t ZSTD_CCtxParam_setParameter( * This function should be updated whenever ZSTD_CCtx_params is updated. * Parameters are copied manually before the dictionary is loaded. * The multithreading parameters jobSize and overlapSizeLog are set only if - * nbThreads >= 1. + * nbThreads > 1. * * Pledged srcSize is treated as unknown. */ @@ -3735,8 +3735,8 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, return cdict; } -ZSTD_CCtx_params ZSTD_getCCtxParamsFromCDict(const ZSTD_CDict* cdict) { - return cdict->refContext->appliedParams; +ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) { + return cdict->refContext->appliedParams.cParams; } /* ZSTD_compressBegin_usingCDict_advanced() : @@ -3746,7 +3746,8 @@ size_t ZSTD_compressBegin_usingCDict_advanced( ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) { if (cdict==NULL) return ERROR(dictionary_wrong); - { ZSTD_CCtx_params params = ZSTD_getCCtxParamsFromCDict(cdict); + { ZSTD_CCtx_params params = cctx->requestedParams; + params.cParams = ZSTD_getCParamsFromCDict(cdict); params.fParams = fParams; params.dictMode = ZSTD_dm_auto; DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced"); @@ -3892,8 +3893,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); } else { if (cdict) { - ZSTD_CCtx_params const cdictParams = ZSTD_getCCtxParamsFromCDict(cdict); - params.cParams = cdictParams.cParams; /* cParams are enforced from cdict */ + params.cParams = ZSTD_getCParamsFromCDict(cdict); /* cParams are enforced from cdict */ } ZSTD_freeCDict(zcs->cdictLocal); zcs->cdictLocal = NULL; @@ -3914,7 +3914,8 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) { /* cannot handle NULL cdict (does not know what to do) */ if (!cdict) return ERROR(dictionary_wrong); - { ZSTD_CCtx_params params = ZSTD_getCCtxParamsFromCDict(cdict); + { ZSTD_CCtx_params params = zcs->requestedParams; + params.cParams = ZSTD_getCParamsFromCDict(cdict); params.fParams = fParams; return ZSTD_initCStream_internal(zcs, NULL, 0, cdict, diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 8687ea3c0..b1a681e74 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -817,7 +817,7 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize) { ZSTD_CCtx_params cctxParams = mtctx->params; - cctxParams.cParams = ZSTD_getCCtxParamsFromCDict(cdict).cParams; + cctxParams.cParams = ZSTD_getCParamsFromCDict(cdict); cctxParams.fParams = fParams; if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */ return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, cdict, From cf689b84f9ffc1eed65a16520b96185845fe0644 Mon Sep 17 00:00:00 2001 From: "Bernhard M. Wiedemann" Date: Sat, 26 Aug 2017 17:08:00 +0200 Subject: [PATCH 058/248] Sort input file list in order to make builds reproducible in spite of indeterministic filesystem readdir order. See https://reproducible-builds.org/ for why this is good. --- lib/Makefile | 2 +- programs/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 5845cf170..e31ce0438 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -31,7 +31,7 @@ CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) FLAGS = $(CPPFLAGS) $(CFLAGS) -ZSTD_FILES := $(wildcard common/*.c compress/*.c decompress/*.c dictBuilder/*.c deprecated/*.c) +ZSTD_FILES := $(sort $(wildcard common/*.c compress/*.c decompress/*.c dictBuilder/*.c deprecated/*.c)) ZSTD_LEGACY_SUPPORT ?= 4 diff --git a/programs/Makefile b/programs/Makefile index c5469cfc4..5fd3703d4 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -68,7 +68,7 @@ endif else endif -ZSTDLIB_FILES := $(wildcard $(ZSTD_FILES)) $(wildcard $(ZSTDLEGACY_FILES)) $(wildcard $(ZDICT_FILES)) +ZSTDLIB_FILES := $(sort $(wildcard $(ZSTD_FILES)) $(wildcard $(ZSTDLEGACY_FILES)) $(wildcard $(ZDICT_FILES))) ZSTDLIB_OBJ := $(patsubst %.c,%.o,$(ZSTDLIB_FILES)) # Define *.exe as extension for Windows systems From 7c365eb02c2eda99fde29a9e0894b667611556b2 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 25 Aug 2017 17:44:32 -0700 Subject: [PATCH 059/248] [threading] Fix ERROR macro after including windows.h --- lib/common/error_private.h | 3 ++- lib/common/threading.h | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/common/error_private.h b/lib/common/error_private.h index 9dd9a87cf..f8e68016a 100644 --- a/lib/common/error_private.h +++ b/lib/common/error_private.h @@ -51,7 +51,8 @@ typedef ZSTD_ErrorCode ERR_enum; #ifdef ERROR # undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ #endif -#define ERROR(name) ((size_t)-PREFIX(name)) +#define ERROR(name) ZSTD_ERROR(name) +#define ZSTD_ERROR(name) ((size_t)-PREFIX(name)) ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } diff --git a/lib/common/threading.h b/lib/common/threading.h index ab09977a8..0a9fcf857 100644 --- a/lib/common/threading.h +++ b/lib/common/threading.h @@ -37,7 +37,15 @@ extern "C" { # define WIN32_LEAN_AND_MEAN #endif +#ifdef ERROR +# undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ +#endif #include +#ifdef ERROR +# undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ +#endif +#define ERROR(name) ZSTD_ERROR(name) + /* mutex */ #define pthread_mutex_t CRITICAL_SECTION From 02033be08c581ec59d4ef26d46defc0687d15f81 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Mon, 28 Aug 2017 17:19:01 -0700 Subject: [PATCH 060/248] [pool] Visual Studios disallows empty structs --- lib/common/pool.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/common/pool.c b/lib/common/pool.c index ada9b1696..9567d112f 100644 --- a/lib/common/pool.c +++ b/lib/common/pool.c @@ -219,7 +219,9 @@ void POOL_add(void* ctxVoid, POOL_function function, void *opaque) { /* No multi-threading support */ /* We don't need any data, but if it is empty malloc() might return NULL. */ -struct POOL_ctx_s {}; +struct POOL_ctx_s { + int dummy; +}; static POOL_ctx g_ctx; POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { From 0e56a84a1ea5c22530eeafe8938d8f56e45cce4b Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Mon, 28 Aug 2017 19:25:17 -0700 Subject: [PATCH 061/248] Fix getting cParams from CCtxParams --- lib/compress/zstd_compress.c | 47 ++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 1f570a92a..4a8e9c8bd 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -197,12 +197,19 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) /* private API call, for dictBuilder only */ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } - #define ZSTD_CLEVEL_CUSTOM 999 + +static ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( + ZSTD_CCtx_params params, U64 srcSizeHint, size_t dictSize) +{ + return (params.compressionLevel == ZSTD_CLEVEL_CUSTOM ? + params.cParams : + ZSTD_getCParams(params.compressionLevel, srcSizeHint, dictSize)); +} + static void ZSTD_cLevelToCCtxParams_srcSize(ZSTD_CCtx_params* params, U64 srcSize) { - if (params->compressionLevel == ZSTD_CLEVEL_CUSTOM) return; - params->cParams = ZSTD_getCParams(params->compressionLevel, srcSize, 0); + params->cParams = ZSTD_getCParamsFromCCtxParams(*params, srcSize, 0); params->compressionLevel = ZSTD_CLEVEL_CUSTOM; } @@ -254,15 +261,14 @@ size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params) { - if (!params) { return ERROR(GENERIC); } - memset(params, 0, sizeof(ZSTD_CCtx_params)); - params->compressionLevel = ZSTD_CLEVEL_DEFAULT; - return 0; + return ZSTD_initCCtxParams(params, ZSTD_CLEVEL_DEFAULT); } size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, int compressionLevel) { - ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0); - return ZSTD_initCCtxParams_advanced(cctxParams, params); + if (!cctxParams) { return ERROR(GENERIC); } + memset(cctxParams, 0, sizeof(ZSTD_CCtx_params)); + cctxParams->compressionLevel = compressionLevel; + return 0; } size_t ZSTD_initCCtxParams_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) @@ -530,9 +536,7 @@ size_t ZSTD_CCtx_loadDictionary_internal( cctx->cdict = NULL; } else { ZSTD_compressionParameters const cParams = - cctx->requestedParams.compressionLevel == ZSTD_CLEVEL_CUSTOM ? - cctx->requestedParams.cParams : - ZSTD_getCParams(cctx->requestedParams.compressionLevel, 0, dictSize); + ZSTD_getCParamsFromCCtxParams(cctx->requestedParams, 0, dictSize); cctx->cdictLocal = ZSTD_createCDict_advanced( dict, dictSize, byReference, @@ -672,7 +676,8 @@ size_t ZSTD_estimateCCtxSize_advanced_opaque(const ZSTD_CCtx_params* params) if (params->nbThreads > 1) { return 0; } - { ZSTD_compressionParameters const cParams = params->cParams; + { ZSTD_compressionParameters const cParams = + ZSTD_getCParamsFromCCtxParams(*params, 0, 0); size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); U32 const divider = (cParams.searchLength==3) ? 3 : 4; size_t const maxNbSeq = blockSize / divider; @@ -3182,10 +3187,8 @@ size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) { - U32 const cLevel = cctx->appliedParams.compressionLevel; - ZSTD_compressionParameters cParams = (cLevel == ZSTD_CLEVEL_CUSTOM) ? - cctx->appliedParams.cParams : - ZSTD_getCParams(cLevel, 0, 0); + ZSTD_compressionParameters cParams = + ZSTD_getCParamsFromCCtxParams(cctx->appliedParams, 0, 0); return MIN (ZSTD_BLOCKSIZE_MAX, 1 << cParams.windowLog); } @@ -3859,10 +3862,8 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) { ZSTD_CCtx_params params = zcs->requestedParams; params.fParams.contentSizeFlag = (pledgedSrcSize > 0); + params.cParams = ZSTD_getCParamsFromCCtxParams(params, pledgedSrcSize, 0); DEBUGLOG(5, "ZSTD_resetCStream"); - if (params.compressionLevel != ZSTD_CLEVEL_CUSTOM) { - params.cParams = ZSTD_getCParams(params.compressionLevel, pledgedSrcSize, 0 /* dictSize */); - } return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->cdict, params, pledgedSrcSize); } @@ -4152,9 +4153,8 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, const void* const prefix = cctx->prefix; size_t const prefixSize = cctx->prefixSize; ZSTD_CCtx_params params = cctx->requestedParams; - if (params.compressionLevel != ZSTD_CLEVEL_CUSTOM) - params.cParams = ZSTD_getCParams(params.compressionLevel, - cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); + params.cParams = ZSTD_getCParamsFromCCtxParams( + cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); cctx->prefix = NULL; cctx->prefixSize = 0; /* single usage */ assert(prefix==NULL || cctx->cdict==NULL); /* only one can be set */ @@ -4382,6 +4382,7 @@ ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long l if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL; { ZSTD_compressionParameters const cp = ZSTD_defaultCParameters[tableID][compressionLevel]; return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); } + } /*! ZSTD_getParams() : From 394bdd7db9c13c9fadad704e7535b3588c650d97 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 29 Aug 2017 09:24:11 -0700 Subject: [PATCH 062/248] changed license for examples intentionnally this time --- LICENSE-examples | 11 ----------- .../seekable_format/examples/parallel_compression.c | 9 +++++---- .../seekable_format/examples/parallel_processing.c | 9 +++++---- .../seekable_format/examples/seekable_compression.c | 9 +++++---- .../seekable_format/examples/seekable_decompression.c | 9 +++++---- examples/dictionary_compression.c | 9 +++++---- examples/dictionary_decompression.c | 9 +++++---- examples/multiple_streaming_compression.c | 9 +++++---- examples/simple_compression.c | 9 +++++---- examples/simple_decompression.c | 9 +++++---- examples/streaming_compression.c | 9 +++++---- examples/streaming_decompression.c | 9 +++++---- 12 files changed, 55 insertions(+), 55 deletions(-) delete mode 100644 LICENSE-examples diff --git a/LICENSE-examples b/LICENSE-examples deleted file mode 100644 index 1de781305..000000000 --- a/LICENSE-examples +++ /dev/null @@ -1,11 +0,0 @@ -Copyright (c) 2016-present, Facebook, Inc. All rights reserved. - -The examples provided by Facebook are for non-commercial testing and evaluation -purposes only. Facebook reserves all rights not expressly granted. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/contrib/seekable_format/examples/parallel_compression.c b/contrib/seekable_format/examples/parallel_compression.c index 89a13185f..69644d2b3 100644 --- a/contrib/seekable_format/examples/parallel_compression.c +++ b/contrib/seekable_format/examples/parallel_compression.c @@ -1,9 +1,10 @@ -/** - * Copyright 2017-present, Facebook, Inc. +/* + * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the license found in the - * LICENSE-examples file in the root directory of this source tree. + * 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). */ #include // malloc, free, exit, atoi diff --git a/contrib/seekable_format/examples/parallel_processing.c b/contrib/seekable_format/examples/parallel_processing.c index cea4d5364..da3477632 100644 --- a/contrib/seekable_format/examples/parallel_processing.c +++ b/contrib/seekable_format/examples/parallel_processing.c @@ -1,9 +1,10 @@ -/** - * Copyright 2017-present, Facebook, Inc. +/* + * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the license found in the - * LICENSE-examples file in the root directory of this source tree. + * 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). */ /* diff --git a/contrib/seekable_format/examples/seekable_compression.c b/contrib/seekable_format/examples/seekable_compression.c index a33952d93..9485bf26f 100644 --- a/contrib/seekable_format/examples/seekable_compression.c +++ b/contrib/seekable_format/examples/seekable_compression.c @@ -1,9 +1,10 @@ -/** - * Copyright 2017-present, Facebook, Inc. +/* + * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the license found in the - * LICENSE-examples file in the root directory of this source tree. + * 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). */ #include // malloc, free, exit, atoi diff --git a/contrib/seekable_format/examples/seekable_decompression.c b/contrib/seekable_format/examples/seekable_decompression.c index b765a7591..9cd232922 100644 --- a/contrib/seekable_format/examples/seekable_decompression.c +++ b/contrib/seekable_format/examples/seekable_decompression.c @@ -1,9 +1,10 @@ -/** - * Copyright 2016-present, Yann Collet, Facebook, Inc. +/* + * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the license found in the - * LICENSE-examples file in the root directory of this source tree. + * 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). */ diff --git a/examples/dictionary_compression.c b/examples/dictionary_compression.c index adcc3b4d5..17acec98d 100644 --- a/examples/dictionary_compression.c +++ b/examples/dictionary_compression.c @@ -1,9 +1,10 @@ -/** - * Copyright 2016-present, Yann Collet, Facebook, Inc. +/* + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the license found in the - * LICENSE-examples file in the root directory of this source tree. + * 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). */ diff --git a/examples/dictionary_decompression.c b/examples/dictionary_decompression.c index ef739c189..345c968c3 100644 --- a/examples/dictionary_decompression.c +++ b/examples/dictionary_decompression.c @@ -1,9 +1,10 @@ -/** - * Copyright 2016-present, Yann Collet, Facebook, Inc. +/* + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the license found in the - * LICENSE-examples file in the root directory of this source tree. + * 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). */ diff --git a/examples/multiple_streaming_compression.c b/examples/multiple_streaming_compression.c index 61699104c..7bfa133ee 100644 --- a/examples/multiple_streaming_compression.c +++ b/examples/multiple_streaming_compression.c @@ -1,9 +1,10 @@ -/** - * Copyright 2016-present, Yann Collet, Facebook, Inc. +/* + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the license found in the - * LICENSE-examples file in the root directory of this source tree. + * 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). */ diff --git a/examples/simple_compression.c b/examples/simple_compression.c index ab1131475..95853faa6 100644 --- a/examples/simple_compression.c +++ b/examples/simple_compression.c @@ -1,9 +1,10 @@ -/** - * Copyright 2016-present, Yann Collet, Facebook, Inc. +/* + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the license found in the - * LICENSE-examples file in the root directory of this source tree. + * 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). */ diff --git a/examples/simple_decompression.c b/examples/simple_decompression.c index 4b7ea59e5..9e9fcc9ed 100644 --- a/examples/simple_decompression.c +++ b/examples/simple_decompression.c @@ -1,9 +1,10 @@ -/** - * Copyright 2016-present, Yann Collet, Facebook, Inc. +/* + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the license found in the - * LICENSE-examples file in the root directory of this source tree. + * 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). */ #include // malloc, exit diff --git a/examples/streaming_compression.c b/examples/streaming_compression.c index 24ad15bd6..ac7ee7687 100644 --- a/examples/streaming_compression.c +++ b/examples/streaming_compression.c @@ -1,9 +1,10 @@ -/** - * Copyright 2016-present, Yann Collet, Facebook, Inc. +/* + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the license found in the - * LICENSE-examples file in the root directory of this source tree. + * 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). */ diff --git a/examples/streaming_decompression.c b/examples/streaming_decompression.c index bb2d80987..76dd85169 100644 --- a/examples/streaming_decompression.c +++ b/examples/streaming_decompression.c @@ -1,9 +1,10 @@ -/** - * Copyright 2016-present, Yann Collet, Facebook, Inc. +/* + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the license found in the - * LICENSE-examples file in the root directory of this source tree. + * 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). */ From b5b9275e6780107aaf54212a038b3daeba247400 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Tue, 29 Aug 2017 10:49:29 -0700 Subject: [PATCH 063/248] Rename estimateCCtxSize_advanced() and estimateCStreamSize_advanced() --- lib/compress/zstd_compress.c | 25 +++++++++++++------------ lib/zstd.h | 26 +++++++++++++------------- tests/paramgrill.c | 4 ++-- tests/zstreamtest.c | 2 +- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 4a8e9c8bd..26de0efd8 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -670,7 +670,7 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); } -size_t ZSTD_estimateCCtxSize_advanced_opaque(const ZSTD_CCtx_params* params) +size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params) { /* Estimate CCtx size is supported for single-threaded compression only. */ if (params->nbThreads > 1) { @@ -703,24 +703,24 @@ size_t ZSTD_estimateCCtxSize_advanced_opaque(const ZSTD_CCtx_params* params) } } -size_t ZSTD_estimateCCtxSize_advanced(ZSTD_compressionParameters cParams) +size_t ZSTD_estimateCCtxSize_advanced_usingCParams(ZSTD_compressionParameters cParams) { ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); - return ZSTD_estimateCCtxSize_advanced_opaque(¶ms); + return ZSTD_estimateCCtxSize_advanced_usingCCtxParams(¶ms); } size_t ZSTD_estimateCCtxSize(int compressionLevel) { ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); - return ZSTD_estimateCCtxSize_advanced(cParams); + return ZSTD_estimateCCtxSize_advanced_usingCParams(cParams); } -size_t ZSTD_estimateCStreamSize_advanced_opaque(const ZSTD_CCtx_params* params) +size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params) { if (params->nbThreads > 1) { return 0; } - { size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced_opaque(params); + { size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced_usingCCtxParams(params); size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog); size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize; size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; @@ -730,15 +730,15 @@ size_t ZSTD_estimateCStreamSize_advanced_opaque(const ZSTD_CCtx_params* params) } } -size_t ZSTD_estimateCStreamSize_advanced(ZSTD_compressionParameters cParams) +size_t ZSTD_estimateCStreamSize_advanced_usingCParams(ZSTD_compressionParameters cParams) { ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); - return ZSTD_estimateCStreamSize_advanced_opaque(¶ms); + return ZSTD_estimateCStreamSize_advanced_usingCCtxParams(¶ms); } size_t ZSTD_estimateCStreamSize(int compressionLevel) { ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); - return ZSTD_estimateCStreamSize_advanced(cParams); + return ZSTD_estimateCStreamSize_advanced_usingCParams(cParams); } static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1, @@ -3585,8 +3585,9 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcS size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference) { DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict)); - DEBUGLOG(5, "CCtx estimate : %u", (U32)ZSTD_estimateCCtxSize_advanced(cParams)); - return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced(cParams) + DEBUGLOG(5, "CCtx estimate : %u", + (U32)ZSTD_estimateCCtxSize_advanced_usingCParams(cParams)); + return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced_usingCParams(cParams) + (byReference ? 0 : dictSize); } @@ -3709,7 +3710,7 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, unsigned byReference, ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams) { - size_t const cctxSize = ZSTD_estimateCCtxSize_advanced(cParams); + size_t const cctxSize = ZSTD_estimateCCtxSize_advanced_usingCParams(cParams); size_t const neededSize = sizeof(ZSTD_CDict) + (byReference ? 0 : dictSize) + cctxSize; ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; diff --git a/lib/zstd.h b/lib/zstd.h index 0c970f3f9..6d91e92a4 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -496,21 +496,21 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); * of a future {D,C}Ctx, before its creation. * ZSTD_estimateCCtxSize() will provide a budget large enough for any compression level up to selected one. * It will also consider src size to be arbitrarily "large", which is worst case. - * If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced() can provide a tighter estimation. - * ZSTD_estimateCCtxSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - * ZSTD_estimateCCtxSize_advanced_opaque() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return 0 if ZSTD_p_nbThreads is set to a value > 1. + * If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced_usingCParams() can provide a tighter estimation. + * ZSTD_estimateCCtxSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + * ZSTD_estimateCCtxSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return 0 if ZSTD_p_nbThreads is set to a value > 1. * Note : CCtx estimation is only correct for single-threaded compression */ ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel); -ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced(ZSTD_compressionParameters cParams); -ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced_opaque(const ZSTD_CCtx_params* params); +ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params); ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); -/*! ZSTD_estimate?StreamSize() : +/*! ZSTD_estimateCStreamSize() : * ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one. * It will also consider src size to be arbitrarily "large", which is worst case. - * If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced() can provide a tighter estimation. - * ZSTD_estimateCStreamSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - * ZSTD_estimateCStreamSize_advanced_opaque() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return 0 if ZSTD_p_nbThreads is set to a value > 1. + * If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced_usingCParams() can provide a tighter estimation. + * ZSTD_estimateCStreamSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + * ZSTD_estimateCStreamSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return 0 if ZSTD_p_nbThreads is set to a value > 1. * Note : CStream estimation is only correct for single-threaded compression. * ZSTD_DStream memory budget depends on window Size. * This information can be passed manually, using ZSTD_estimateDStreamSize, @@ -519,14 +519,14 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); * an internal ?Dict will be created, which additional size is not estimated here. * In this case, get total size by adding ZSTD_estimate?DictSize */ ZSTDLIB_API size_t ZSTD_estimateCStreamSize(int compressionLevel); -ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced(ZSTD_compressionParameters cParams); -ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced_opaque(const ZSTD_CCtx_params* params); +ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params); ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize); ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); -/*! ZSTD_estimate?DictSize() : +/*! ZSTD_estimateCDictSize() : * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). - * ZSTD_estimateCStreamSize_advanced() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced(). + * ZSTD_estimateCStreamSize_advanced_usingCParams() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced(). * Note : dictionary created "byReference" are smaller */ ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference); diff --git a/tests/paramgrill.c b/tests/paramgrill.c index da06ccb52..1818e5121 100644 --- a/tests/paramgrill.c +++ b/tests/paramgrill.c @@ -390,8 +390,8 @@ static int BMK_seed(winnerInfo_t* winners, const ZSTD_compressionParameters para double W_DMemUsed_note = W_ratioNote * ( 40 + 9*cLevel) - log((double)W_DMemUsed); double O_DMemUsed_note = O_ratioNote * ( 40 + 9*cLevel) - log((double)O_DMemUsed); - size_t W_CMemUsed = (1 << params.windowLog) + ZSTD_estimateCCtxSize_advanced(params); - size_t O_CMemUsed = (1 << winners[cLevel].params.windowLog) + ZSTD_estimateCCtxSize_advanced(winners[cLevel].params); + size_t W_CMemUsed = (1 << params.windowLog) + ZSTD_estimateCCtxSize_advanced_usingCParams(params); + size_t O_CMemUsed = (1 << winners[cLevel].params.windowLog) + ZSTD_estimateCCtxSize_advanced_usingCParams(winners[cLevel].params); double W_CMemUsed_note = W_ratioNote * ( 50 + 13*cLevel) - log((double)W_CMemUsed); double O_CMemUsed_note = O_ratioNote * ( 50 + 13*cLevel) - log((double)O_CMemUsed); diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 0373676d0..0bf833c51 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -197,7 +197,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo /* context size functions */ DISPLAYLEVEL(3, "test%3i : estimate CStream size : ", testNb++); { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictSize); - size_t const s = ZSTD_estimateCStreamSize_advanced(cParams) + size_t const s = ZSTD_estimateCStreamSize_advanced_usingCParams(cParams) /* uses ZSTD_initCStream_usingDict() */ + ZSTD_estimateCDictSize_advanced(dictSize, cParams, 0); if (ZSTD_isError(s)) goto _output_error; From 9822f97721e472d711f8e28c7304dac379ccdfb6 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 29 Aug 2017 11:54:38 -0700 Subject: [PATCH 064/248] [error] Don't guard undef X with ifdef X --- lib/common/error_private.h | 4 +--- lib/common/threading.h | 8 ++------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/common/error_private.h b/lib/common/error_private.h index f8e68016a..a55bce847 100644 --- a/lib/common/error_private.h +++ b/lib/common/error_private.h @@ -48,9 +48,7 @@ typedef ZSTD_ErrorCode ERR_enum; /*-**************************************** * Error codes handling ******************************************/ -#ifdef ERROR -# undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ -#endif +#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ #define ERROR(name) ZSTD_ERROR(name) #define ZSTD_ERROR(name) ((size_t)-PREFIX(name)) diff --git a/lib/common/threading.h b/lib/common/threading.h index 0a9fcf857..bd4b654c2 100644 --- a/lib/common/threading.h +++ b/lib/common/threading.h @@ -37,13 +37,9 @@ extern "C" { # define WIN32_LEAN_AND_MEAN #endif -#ifdef ERROR -# undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ -#endif +#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ #include -#ifdef ERROR -# undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ -#endif +#undef ERROR #define ERROR(name) ZSTD_ERROR(name) From c88fb9267f6bad0d0477960d535a553ee33b7840 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Tue, 29 Aug 2017 11:55:02 -0700 Subject: [PATCH 065/248] Replace 'byReference' with enum --- lib/compress/zstd_compress.c | 40 ++++++++++++++++++------------- lib/compress/zstdmt_compress.c | 2 +- lib/decompress/zstd_decompress.c | 27 +++++++++++---------- lib/zstd.h | 28 ++++++++++++++-------- programs/bench.c | 2 +- tests/fuzzer.c | 18 +++++++------- tests/zstreamtest.c | 6 ++--- zlibWrapper/examples/zwrapbench.c | 2 +- 8 files changed, 70 insertions(+), 55 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 26de0efd8..511d1c3a0 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -525,7 +525,8 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo } size_t ZSTD_CCtx_loadDictionary_internal( - ZSTD_CCtx* cctx, const void* dict, size_t dictSize, unsigned byReference) + ZSTD_CCtx* cctx, const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod) { if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */ @@ -539,7 +540,7 @@ size_t ZSTD_CCtx_loadDictionary_internal( ZSTD_getCParamsFromCCtxParams(cctx->requestedParams, 0, dictSize); cctx->cdictLocal = ZSTD_createCDict_advanced( dict, dictSize, - byReference, + dictLoadMethod, cctx->requestedParams.dictMode, cParams, cctx->customMem); cctx->cdict = cctx->cdictLocal; @@ -552,12 +553,12 @@ size_t ZSTD_CCtx_loadDictionary_internal( ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference( ZSTD_CCtx* cctx, const void* dict, size_t dictSize) { - return ZSTD_CCtx_loadDictionary_internal(cctx, dict, dictSize, 1); + return ZSTD_CCtx_loadDictionary_internal(cctx, dict, dictSize, ZSTD_dlm_byRef); } ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) { - return ZSTD_CCtx_loadDictionary_internal(cctx, dict, dictSize, 0); + return ZSTD_CCtx_loadDictionary_internal(cctx, dict, dictSize, ZSTD_dlm_byCopy); } @@ -3582,13 +3583,15 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcS /*! ZSTD_estimateCDictSize_advanced() : * Estimate amount of memory that will be needed to create a dictionary with following arguments */ -size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference) +size_t ZSTD_estimateCDictSize_advanced( + size_t dictSize, ZSTD_compressionParameters cParams, + ZSTD_dictLoadMethod_e dictLoadMethod) { DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict)); DEBUGLOG(5, "CCtx estimate : %u", (U32)ZSTD_estimateCCtxSize_advanced_usingCParams(cParams)); return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced_usingCParams(cParams) - + (byReference ? 0 : dictSize); + + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); } size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) @@ -3608,11 +3611,12 @@ size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) static size_t ZSTD_initCDict_internal( ZSTD_CDict* cdict, const void* dictBuffer, size_t dictSize, - unsigned byReference, ZSTD_dictMode_e dictMode, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams) { DEBUGLOG(5, "ZSTD_initCDict_internal, mode %u", (U32)dictMode); - if ((byReference) || (!dictBuffer) || (!dictSize)) { + if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { cdict->dictBuffer = NULL; cdict->dictContent = dictBuffer; } else { @@ -3640,7 +3644,8 @@ static size_t ZSTD_initCDict_internal( } ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, - unsigned byReference, ZSTD_dictMode_e dictMode, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams, ZSTD_customMem customMem) { DEBUGLOG(5, "ZSTD_createCDict_advanced, mode %u", (U32)dictMode); @@ -3656,7 +3661,7 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, cdict->refContext = cctx; if (ZSTD_isError( ZSTD_initCDict_internal(cdict, dictBuffer, dictSize, - byReference, dictMode, + dictLoadMethod, dictMode, cParams) )) { ZSTD_freeCDict(cdict); return NULL; @@ -3669,7 +3674,7 @@ ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionL { ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); return ZSTD_createCDict_advanced(dict, dictSize, - 0 /* byReference */, ZSTD_dm_auto, + ZSTD_dlm_byCopy, ZSTD_dm_auto, cParams, ZSTD_defaultCMem); } @@ -3677,7 +3682,7 @@ ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int { ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); return ZSTD_createCDict_advanced(dict, dictSize, - 1 /* byReference */, ZSTD_dm_auto, + ZSTD_dlm_byRef, ZSTD_dm_auto, cParams, ZSTD_defaultCMem); } @@ -3707,11 +3712,12 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict) */ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, const void* dict, size_t dictSize, - unsigned byReference, ZSTD_dictMode_e dictMode, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams) { size_t const cctxSize = ZSTD_estimateCCtxSize_advanced_usingCParams(cParams); - size_t const neededSize = sizeof(ZSTD_CDict) + (byReference ? 0 : dictSize) + size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize) + cctxSize; ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; void* ptr; @@ -3721,7 +3727,7 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize)); if (workspaceSize < neededSize) return NULL; - if (!byReference) { + if (dictLoadMethod == ZSTD_dlm_byCopy) { memcpy(cdict+1, dict, dictSize); dict = cdict+1; ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize; @@ -3732,7 +3738,7 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize, if (ZSTD_isError( ZSTD_initCDict_internal(cdict, dict, dictSize, - 1 /* byReference */, dictMode, + ZSTD_dlm_byRef, dictMode, cParams) )) return NULL; @@ -3889,7 +3895,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, ZSTD_freeCDict(zcs->cdictLocal); zcs->cdictLocal = ZSTD_createCDict_advanced( dict, dictSize, - 0 /* byReference */, params.dictMode, + ZSTD_dlm_byCopy, params.dictMode, params.cParams, zcs->customMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index b1a681e74..e64a1f694 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -768,7 +768,7 @@ size_t ZSTDMT_initCStream_internal( DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal); ZSTD_freeCDict(zcs->cdictLocal); zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, - 0 /* byRef */, ZSTD_dm_auto, /* note : a loadPrefix becomes an internal CDict */ + ZSTD_dlm_byCopy, ZSTD_dm_auto, /* note : a loadPrefix becomes an internal CDict */ params.cParams, zcs->cMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 92e80c1ac..6f4e72391 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -1993,9 +1993,9 @@ static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict* ddict) } -static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, const void* dict, size_t dictSize, unsigned byReference) +static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod) { - if ((byReference) || (!dict) || (!dictSize)) { + if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dict) || (!dictSize)) { ddict->dictBuffer = NULL; ddict->dictContent = dict; } else { @@ -2014,7 +2014,7 @@ static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, const void* dict, size_ return 0; } -ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, unsigned byReference, ZSTD_customMem customMem) +ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_customMem customMem) { if (!customMem.customAlloc ^ !customMem.customFree) return NULL; @@ -2022,7 +2022,7 @@ ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, unsigne if (!ddict) return NULL; ddict->cMem = customMem; - if (ZSTD_isError( ZSTD_initDDict_internal(ddict, dict, dictSize, byReference) )) { + if (ZSTD_isError( ZSTD_initDDict_internal(ddict, dict, dictSize, dictLoadMethod) )) { ZSTD_freeDDict(ddict); return NULL; } @@ -2038,7 +2038,7 @@ ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, unsigne ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize) { ZSTD_customMem const allocator = { NULL, NULL, NULL }; - return ZSTD_createDDict_advanced(dict, dictSize, 0, allocator); + return ZSTD_createDDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, allocator); } /*! ZSTD_createDDict_byReference() : @@ -2048,25 +2048,26 @@ ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize) ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize) { ZSTD_customMem const allocator = { NULL, NULL, NULL }; - return ZSTD_createDDict_advanced(dictBuffer, dictSize, 1, allocator); + return ZSTD_createDDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, allocator); } ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSize, const void* dict, size_t dictSize, - unsigned byReference) + ZSTD_dictLoadMethod_e dictLoadMethod) { - size_t const neededSpace = sizeof(ZSTD_DDict) + (byReference ? 0 : dictSize); + size_t const neededSpace = + sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); ZSTD_DDict* const ddict = (ZSTD_DDict*)workspace; assert(workspace != NULL); assert(dict != NULL); if ((size_t)workspace & 7) return NULL; /* 8-aligned */ if (workspaceSize < neededSpace) return NULL; - if (!byReference) { + if (dictLoadMethod == ZSTD_dlm_byCopy) { memcpy(ddict+1, dict, dictSize); /* local copy */ dict = ddict+1; } - if (ZSTD_isError( ZSTD_initDDict_internal(ddict, dict, dictSize, 1 /* byRef */) )) + if (ZSTD_isError( ZSTD_initDDict_internal(ddict, dict, dictSize, ZSTD_dlm_byRef) )) return NULL; return ddict; } @@ -2084,10 +2085,10 @@ size_t ZSTD_freeDDict(ZSTD_DDict* ddict) /*! ZSTD_estimateDDictSize() : * Estimate amount of memory that will be needed to create a dictionary for decompression. - * Note : dictionary created "byReference" are smaller */ -size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference) + * Note : dictionary created by reference using ZSTD_dlm_byRef are smaller */ +size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod) { - return sizeof(ZSTD_DDict) + (byReference ? 0 : dictSize); + return sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); } size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict) diff --git a/lib/zstd.h b/lib/zstd.h index 6d91e92a4..9ff8ad99f 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -524,13 +524,19 @@ ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_ ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize); ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); -/*! ZSTD_estimateCDictSize() : +typedef enum { + ZSTD_dlm_byCopy = 0, /* Copy dictionary content internally. */ + ZSTD_dlm_byRef, /* Reference dictionary content -- the dictionary buffer must outlives its users. */ +} ZSTD_dictLoadMethod_e; + +/*! ZSTD_estimate?DictSize() : * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). * ZSTD_estimateCStreamSize_advanced_usingCParams() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced(). - * Note : dictionary created "byReference" are smaller */ + * Note : dictionary created by reference using ZSTD_dlm_byRef are smaller + */ ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); -ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference); -ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference); +ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod); +ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod); /*************************************** @@ -564,7 +570,6 @@ ZSTDLIB_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize * It is important that dictBuffer outlives CDict, it must remain read accessible throughout the lifetime of CDict */ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel); - typedef enum { ZSTD_dm_auto=0, /* dictionary is "full" if it starts with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */ ZSTD_dm_rawContent, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */ ZSTD_dm_fullDict /* refuses to load a dictionary if it does not respect Zstandard's specification */ @@ -572,7 +577,8 @@ typedef enum { ZSTD_dm_auto=0, /* dictionary is "full" if it starts with /*! ZSTD_createCDict_advanced() : * Create a ZSTD_CDict using external alloc and free, and customized compression parameters */ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, - unsigned byReference, ZSTD_dictMode_e dictMode, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams, ZSTD_customMem customMem); @@ -592,7 +598,7 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictS ZSTDLIB_API ZSTD_CDict* ZSTD_initStaticCDict( void* workspace, size_t workspaceSize, const void* dict, size_t dictSize, - unsigned byReference, ZSTD_dictMode_e dictMode, + ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode, ZSTD_compressionParameters cParams); /*! ZSTD_getCParams() : @@ -670,7 +676,8 @@ ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, siz /*! ZSTD_createDDict_advanced() : * Create a ZSTD_DDict using external alloc and free, optionally by reference */ ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, - unsigned byReference, ZSTD_customMem customMem); + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_customMem customMem); /*! ZSTD_initStaticDDict() : * Generate a digested dictionary in provided memory area. @@ -685,7 +692,7 @@ ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictS */ ZSTDLIB_API ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSize, const void* dict, size_t dictSize, - unsigned byReference); + ZSTD_dictLoadMethod_e dictLoadMethod); /*! ZSTD_getDictID_fromDict() : * Provides the dictID stored within dictionary. @@ -1018,6 +1025,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, s */ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); + /*! ZSTD_CCtx_refCDict() : * Reference a prepared dictionary, to be used for all next compression jobs. * Note that compression parameters are enforced from within CDict, @@ -1096,7 +1104,7 @@ size_t ZSTD_compress_generic_simpleArgs ( ZSTD_EndDirective endOp); -/** ZSTD_CCtx_params : +/** ZSTD_CCtx_params * * - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure * - ZSTD_CCtxParam_setParameter() : Push parameters one by one into an diff --git a/programs/bench.c b/programs/bench.c index f9493e3b0..7731d079e 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -284,7 +284,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, if (comprParams->searchLength) zparams.cParams.searchLength = comprParams->searchLength; if (comprParams->targetLength) zparams.cParams.targetLength = comprParams->targetLength; if (comprParams->strategy) zparams.cParams.strategy = comprParams->strategy; - cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, 1 /*byRef*/, ZSTD_dm_auto, zparams.cParams, cmem); + cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dm_auto, zparams.cParams, cmem); if (cdict==NULL) EXM_THROW(1, "ZSTD_createCDict_advanced() allocation failure"); #endif do { diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 3f7595e99..9f661175a 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -598,10 +598,10 @@ static int basicUnitTests(U32 seed, double compressibility) } DISPLAYLEVEL(4, "test%3i : decompress with static DDict : ", testNb++); - { size_t const ddictBufferSize = ZSTD_estimateDDictSize(dictSize, 0); + { size_t const ddictBufferSize = ZSTD_estimateDDictSize(dictSize, ZSTD_dlm_byCopy); void* ddictBuffer = malloc(ddictBufferSize); if (ddictBuffer == NULL) goto _output_error; - { ZSTD_DDict* const ddict = ZSTD_initStaticDDict(ddictBuffer, ddictBufferSize, CNBuffer, dictSize, 0); + { ZSTD_DDict* const ddict = ZSTD_initStaticDDict(ddictBuffer, ddictBufferSize, CNBuffer, dictSize, ZSTD_dlm_byCopy); size_t const r = ZSTD_decompress_usingDDict(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize, ddict); if (r != CNBuffSize - dictSize) goto _output_error; } @@ -687,14 +687,14 @@ static int basicUnitTests(U32 seed, double compressibility) DISPLAYLEVEL(4, "test%3i : estimate CDict size : ", testNb++); { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize); - size_t const estimatedSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, 1 /*byReference*/); + size_t const estimatedSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byRef); DISPLAYLEVEL(4, "OK : %u \n", (U32)estimatedSize); } DISPLAYLEVEL(4, "test%3i : compress with CDict ", testNb++); { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize); ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize, - 1 /* byReference */, ZSTD_dm_auto, + ZSTD_dlm_byRef, ZSTD_dm_auto, cParams, ZSTD_defaultCMem); DISPLAYLEVEL(4, "(size : %u) : ", (U32)ZSTD_sizeof_CDict(cdict)); cSize = ZSTD_compress_usingCDict(cctx, compressedBuffer, compressedBufferSize, @@ -720,12 +720,12 @@ static int basicUnitTests(U32 seed, double compressibility) DISPLAYLEVEL(4, "test%3i : compress with static CDict : ", testNb++); { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize); - size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, 0); + size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); void* const cdictBuffer = malloc(cdictSize); if (cdictBuffer==NULL) goto _output_error; { ZSTD_CDict* const cdict = ZSTD_initStaticCDict(cdictBuffer, cdictSize, dictBuffer, dictSize, - 0 /* by Reference */, ZSTD_dm_auto, + ZSTD_dlm_byCopy, ZSTD_dm_auto, cParams); if (cdict == NULL) { DISPLAY("ZSTD_initStaticCDict failed "); @@ -745,7 +745,7 @@ static int basicUnitTests(U32 seed, double compressibility) DISPLAYLEVEL(4, "test%3i : ZSTD_compress_usingCDict_advanced, no contentSize, no dictID : ", testNb++); { ZSTD_frameParameters const fParams = { 0 /* frameSize */, 1 /* checksum */, 1 /* noDictID*/ }; ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize); - ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize, 1 /*byRef*/, ZSTD_dm_auto, cParams, ZSTD_defaultCMem); + ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dm_auto, cParams, ZSTD_defaultCMem); cSize = ZSTD_compress_usingCDict_advanced(cctx, compressedBuffer, compressedBufferSize, CNBuffer, CNBuffSize, cdict, fParams); ZSTD_freeCDict(cdict); @@ -796,7 +796,7 @@ static int basicUnitTests(U32 seed, double compressibility) DISPLAYLEVEL(4, "test%3i : Building cdict w/ ZSTD_dm_fullDict on a good dictionary : ", testNb++); { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize); - ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize, 1 /*byRef*/, ZSTD_dm_fullDict, cParams, ZSTD_defaultCMem); + ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dm_fullDict, cParams, ZSTD_defaultCMem); if (cdict==NULL) goto _output_error; ZSTD_freeCDict(cdict); } @@ -804,7 +804,7 @@ static int basicUnitTests(U32 seed, double compressibility) DISPLAYLEVEL(4, "test%3i : Building cdict w/ ZSTD_dm_fullDict on a rawContent (must fail) : ", testNb++); { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBuffSize, dictSize); - ZSTD_CDict* const cdict = ZSTD_createCDict_advanced((const char*)dictBuffer+1, dictSize-1, 1 /*byRef*/, ZSTD_dm_fullDict, cParams, ZSTD_defaultCMem); + ZSTD_CDict* const cdict = ZSTD_createCDict_advanced((const char*)dictBuffer+1, dictSize-1, ZSTD_dlm_byRef, ZSTD_dm_fullDict, cParams, ZSTD_defaultCMem); if (cdict!=NULL) goto _output_error; ZSTD_freeCDict(cdict); } diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 0bf833c51..5d6ef4168 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -199,7 +199,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictSize); size_t const s = ZSTD_estimateCStreamSize_advanced_usingCParams(cParams) /* uses ZSTD_initCStream_usingDict() */ - + ZSTD_estimateCDictSize_advanced(dictSize, cParams, 0); + + ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); if (ZSTD_isError(s)) goto _output_error; DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)s); } @@ -275,7 +275,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo DISPLAYLEVEL(5, " (windowSize : %u) ", (U32)fhi.windowSize); { size_t const s = ZSTD_estimateDStreamSize(fhi.windowSize) /* uses ZSTD_initDStream_usingDict() */ - + ZSTD_estimateDDictSize(dictSize, 0); + + ZSTD_estimateDDictSize(dictSize, ZSTD_dlm_byCopy); if (ZSTD_isError(s)) goto _output_error; DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)s); } } @@ -477,7 +477,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_usingCDict_advanced with masked dictID : ", testNb++); { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictionary.filled); ZSTD_frameParameters const fParams = { 1 /* contentSize */, 1 /* checksum */, 1 /* noDictID */}; - ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, 1 /* byReference */, ZSTD_dm_auto, cParams, customMem); + ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dm_auto, cParams, customMem); size_t const initError = ZSTD_initCStream_usingCDict_advanced(zc, cdict, fParams, CNBufferSize); if (ZSTD_isError(initError)) goto _output_error; cSize = 0; diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index 1fc2117f6..d99424a7e 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -236,7 +236,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize, if (compressor == BMK_ZSTD) { ZSTD_parameters const zparams = ZSTD_getParams(cLevel, avgSize, dictBufferSize); ZSTD_customMem const cmem = { NULL, NULL, NULL }; - ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, 1 /*byRef*/, ZSTD_dm_auto, zparams.cParams, cmem); + ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dm_auto, zparams.cParams, cmem); if (cdict==NULL) EXM_THROW(1, "ZSTD_createCDict_advanced() allocation failure"); do { From c7a18b7c219b10c1ca8b33cd0d3f2614cae7ff54 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Tue, 29 Aug 2017 15:10:42 -0700 Subject: [PATCH 066/248] Localize 'dictMode' from cctx to function param --- lib/common/zstd_internal.h | 4 +- lib/compress/zstd_compress.c | 104 ++++++++++++++++----------------- lib/compress/zstdmt_compress.c | 10 ++-- lib/zstd.h | 23 ++++---- 4 files changed, 69 insertions(+), 72 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index bfec42fad..6097f8e6f 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -293,9 +293,6 @@ struct ZSTD_CCtx_params_s { int compressionLevel; U32 forceWindow; /* force back-references to respect limit of * 1<requestedParams, param, value); - case ZSTD_p_dictMode: - if (cctx->cdict) return ERROR(stage_wrong); /* must be set before loading */ - return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); - case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize, * even when referencing into Dictionary content * default : 0 when using a CDict, 1 when using a Prefix */ @@ -447,15 +448,6 @@ size_t ZSTD_CCtxParam_setParameter( params->fParams.noDictIDFlag = (value == 0); return 0; - case ZSTD_p_dictMode : - /* restrict dictionary mode to "rawContent" or "fullDict" only */ - ZSTD_STATIC_ASSERT((U32)ZSTD_dm_fullDict > (U32)ZSTD_dm_rawContent); - if (value > (unsigned)ZSTD_dm_fullDict) { - return ERROR(parameter_outOfBound); - } - params->dictMode = (ZSTD_dictMode_e)value; - return 0; - case ZSTD_p_forceMaxWindow : params->forceWindow = value > 0; return 0; @@ -496,9 +488,6 @@ size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params cctx->requestedParams.fParams = params->fParams; cctx->requestedParams.compressionLevel = params->compressionLevel; - /* Assume dictionary parameters are validated */ - cctx->requestedParams.dictMode = params->dictMode; - /* Set force window explicitly since it sets cctx->loadedDictEnd */ CHECK_F( ZSTD_CCtx_setParameter( cctx, ZSTD_p_forceMaxWindow, params->forceWindow) ); @@ -524,9 +513,9 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo return 0; } -size_t ZSTD_CCtx_loadDictionary_internal( - ZSTD_CCtx* cctx, const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod) +size_t ZSTD_CCtx_loadDictionary_advanced( + ZSTD_CCtx* cctx, const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode) { if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */ @@ -541,7 +530,7 @@ size_t ZSTD_CCtx_loadDictionary_internal( cctx->cdictLocal = ZSTD_createCDict_advanced( dict, dictSize, dictLoadMethod, - cctx->requestedParams.dictMode, + dictMode, cParams, cctx->customMem); cctx->cdict = cctx->cdictLocal; if (cctx->cdictLocal == NULL) @@ -553,12 +542,14 @@ size_t ZSTD_CCtx_loadDictionary_internal( ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference( ZSTD_CCtx* cctx, const void* dict, size_t dictSize) { - return ZSTD_CCtx_loadDictionary_internal(cctx, dict, dictSize, ZSTD_dlm_byRef); + return ZSTD_CCtx_loadDictionary_advanced( + cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dm_auto); } ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) { - return ZSTD_CCtx_loadDictionary_internal(cctx, dict, dictSize, ZSTD_dlm_byCopy); + return ZSTD_CCtx_loadDictionary_advanced( + cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dm_auto); } @@ -566,20 +557,27 @@ size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) { if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); cctx->cdict = cdict; - cctx->prefix = NULL; /* exclusive */ - cctx->prefixSize = 0; + memset(&cctx->prefixDict, 0, sizeof(ZSTD_prefixDict)); /* exclusive */ return 0; } size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize) +{ + return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dm_rawContent); +} + +size_t ZSTD_CCtx_refPrefix_advanced( + ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode) { if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); cctx->cdict = NULL; /* prefix discards any prior cdict */ - cctx->prefix = prefix; - cctx->prefixSize = prefixSize; + cctx->prefixDict.dict = prefix; + cctx->prefixDict.dictSize = prefixSize; + cctx->prefixDict.dictMode = dictMode; return 0; } + static void ZSTD_startNewCompression(ZSTD_CCtx* cctx) { cctx->streamStage = zcss_init; @@ -3387,13 +3385,14 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx, * @return : 0, or an error code */ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, + ZSTD_dictMode_e dictMode, const ZSTD_CDict* cdict, ZSTD_CCtx_params params, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { DEBUGLOG(4, "ZSTD_compressBegin_internal"); DEBUGLOG(4, "dict ? %s", dict ? "dict" : (cdict ? "cdict" : "none")); - DEBUGLOG(4, "dictMode : %u", (U32)(params.dictMode)); + DEBUGLOG(4, "dictMode : %u", (U32)dictMode); /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ @@ -3406,18 +3405,19 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, ZSTDcrp_continue, zbuff) ); - return ZSTD_compress_insertDictionary(cctx, dict, dictSize, params.dictMode); + return ZSTD_compress_insertDictionary(cctx, dict, dictSize, dictMode); } size_t ZSTD_compressBegin_advanced_internal( ZSTD_CCtx* cctx, const void* dict, size_t dictSize, + ZSTD_dictMode_e dictMode, ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) { /* compression parameters verification and optimization */ CHECK_F( ZSTD_checkCParams(params.cParams) ); - return ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL, + return ZSTD_compressBegin_internal(cctx, dict, dictSize, dictMode, NULL, params, pledgedSrcSize, ZSTDb_not_buffered); } @@ -3430,8 +3430,8 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, { ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); - cctxParams.dictMode = ZSTD_dm_auto; - return ZSTD_compressBegin_advanced_internal(cctx, dict, dictSize, cctxParams, + return ZSTD_compressBegin_advanced_internal(cctx, dict, dictSize, ZSTD_dm_auto, + cctxParams, pledgedSrcSize); } @@ -3440,8 +3440,7 @@ size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t di ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); - cctxParams.dictMode = ZSTD_dm_auto; - return ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL, + return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL, cctxParams, 0, ZSTDb_not_buffered); } @@ -3523,7 +3522,6 @@ static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, { ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); - cctxParams.dictMode = ZSTD_dm_auto; return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, @@ -3549,7 +3547,7 @@ size_t ZSTD_compress_advanced_internal( const void* dict,size_t dictSize, ZSTD_CCtx_params params) { - CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL, + CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL, params, srcSize, ZSTDb_not_buffered) ); return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); } @@ -3633,9 +3631,8 @@ static size_t ZSTD_initCDict_internal( ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams; cctxParams.fParams = fParams; cctxParams.cParams = cParams; - cctxParams.dictMode = dictMode; CHECK_F( ZSTD_compressBegin_internal(cdict->refContext, - cdict->dictContent, dictSize, + cdict->dictContent, dictSize, dictMode, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered) ); @@ -3759,10 +3756,9 @@ size_t ZSTD_compressBegin_usingCDict_advanced( { ZSTD_CCtx_params params = cctx->requestedParams; params.cParams = ZSTD_getCParamsFromCDict(cdict); params.fParams = fParams; - params.dictMode = ZSTD_dm_auto; DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced"); return ZSTD_compressBegin_internal(cctx, - NULL, 0, + NULL, 0, ZSTD_dm_auto, cdict, params, pledgedSrcSize, ZSTDb_not_buffered); @@ -3841,7 +3837,7 @@ size_t ZSTD_CStreamOutSize(void) static size_t ZSTD_resetCStream_internal( ZSTD_CStream* zcs, - const void* dict, size_t dictSize, + const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, const ZSTD_CDict* cdict, const ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) { @@ -3851,7 +3847,7 @@ static size_t ZSTD_resetCStream_internal( assert(!((dict) && (cdict))); /* either dict or cdict, not both */ CHECK_F( ZSTD_compressBegin_internal(zcs, - dict, dictSize, + dict, dictSize, dictMode, cdict, params, pledgedSrcSize, ZSTDb_buffered) ); @@ -3871,7 +3867,7 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) params.fParams.contentSizeFlag = (pledgedSrcSize > 0); params.cParams = ZSTD_getCParamsFromCCtxParams(params, pledgedSrcSize, 0); DEBUGLOG(5, "ZSTD_resetCStream"); - return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->cdict, params, pledgedSrcSize); + return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, zcs->cdict, params, pledgedSrcSize); } /*! ZSTD_initCStream_internal() : @@ -3895,7 +3891,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, ZSTD_freeCDict(zcs->cdictLocal); zcs->cdictLocal = ZSTD_createCDict_advanced( dict, dictSize, - ZSTD_dlm_byCopy, params.dictMode, + ZSTD_dlm_byCopy, ZSTD_dm_auto, params.cParams, zcs->customMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); @@ -3911,7 +3907,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, params.compressionLevel = ZSTD_CLEVEL_CUSTOM; zcs->requestedParams = params; - return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->cdict, params, pledgedSrcSize); + return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, zcs->cdict, params, pledgedSrcSize); } /* ZSTD_initCStream_usingCDict_advanced() : @@ -4157,23 +4153,27 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, /* transparent initialization stage */ if (cctx->streamStage == zcss_init) { - const void* const prefix = cctx->prefix; - size_t const prefixSize = cctx->prefixSize; + ZSTD_prefixDict const prefixDict = cctx->prefixDict; ZSTD_CCtx_params params = cctx->requestedParams; params.cParams = ZSTD_getCParamsFromCCtxParams( cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); - cctx->prefix = NULL; cctx->prefixSize = 0; /* single usage */ - assert(prefix==NULL || cctx->cdict==NULL); /* only one can be set */ + memset(&cctx->prefixDict, 0, sizeof(ZSTD_prefixDict)); /* single usage */ + assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ #ifdef ZSTD_MULTITHREAD if (params.nbThreads > 1) { DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", params.nbThreads); - CHECK_F( ZSTDMT_initCStream_internal(cctx->mtctx, prefix, prefixSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); + CHECK_F( ZSTDMT_initCStream_internal( + cctx->mtctx, prefixDict.dict, prefixDict.dictSize, + cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); cctx->streamStage = zcss_load; } else #endif { - CHECK_F( ZSTD_resetCStream_internal(cctx, prefix, prefixSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); + CHECK_F( ZSTD_resetCStream_internal( + cctx, prefixDict.dict, prefixDict.dictSize, + prefixDict.dictMode, cctx->cdict, params, + cctx->pledgedSrcSizePlusOne-1) ); } } /* compression stage */ diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index e64a1f694..41278677f 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -343,13 +343,13 @@ void ZSTDMT_compressChunk(void* jobDescription) if (!job->firstChunk) job->params.fParams.contentSizeFlag = 0; /* ensure no srcSize control */ { ZSTD_CCtx_params jobParams = job->params; /* Force loading dictionary in "content-only" mode (no header analysis) */ - size_t const dictModeError = - ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_dictMode, (U32)ZSTD_dm_rawContent); size_t const forceWindowError = ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk); - size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, job->srcStart, job->dictSize, jobParams, job->fullFrameSize); - if (ZSTD_isError(initError) || ZSTD_isError(dictModeError) || - ZSTD_isError(forceWindowError)) { job->cSize = initError; goto _endJob; } + size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, job->srcStart, job->dictSize, ZSTD_dm_rawContent, jobParams, job->fullFrameSize); + if (ZSTD_isError(initError) || ZSTD_isError(forceWindowError)) { + job->cSize = initError; + goto _endJob; + } } } if (!job->firstChunk) { /* flush and overwrite frame header when it's not first segment */ size_t const hSize = ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, 0); diff --git a/lib/zstd.h b/lib/zstd.h index 9ff8ad99f..8ac564884 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -963,10 +963,6 @@ typedef enum { ZSTD_p_checksumFlag, /* A 32-bits checksum of content is written at end of frame (default:0) */ ZSTD_p_dictIDFlag, /* When applicable, dictID of dictionary is provided in frame header (default:1) */ - /* dictionary parameters (must be set before ZSTD_CCtx_loadDictionary) */ - ZSTD_p_dictMode=300, /* Select how dictionary content must be interpreted. Value must be from type ZSTD_dictMode_e. - * default : 0==auto : dictionary will be "full" if it respects specification, otherwise it will be "rawContent" */ - /* multi-threading parameters */ ZSTD_p_nbThreads=400, /* Select how many threads a compression job can spawn (default:1) * More threads improve speed, but also increase memory usage. @@ -1011,19 +1007,19 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo * meaning "return to no-dictionary mode". * Note 1 : `dict` content will be copied internally. Use * ZSTD_CCtx_loadDictionary_byReference() to reference dictionary - * content instead. + * content instead. The dictionary buffer must then outlive its + * users. * Note 2 : Loading a dictionary involves building tables, which are dependent on compression parameters. * For this reason, compression parameters cannot be changed anymore after loading a dictionary. * It's also a CPU-heavy operation, with non-negligible impact on latency. * Note 3 : Dictionary will be used for all future compression jobs. - * To return to "no-dictionary" situation, load a NULL dictionary */ -ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); - -/*! ZSTD_CCtx_loadDictionary_byReference() : - * Same as ZSTD_CCtx_loadDictionary() except dictionary content will be - * referenced, instead of copied. The dictionary buffer must outlive its users. + * To return to "no-dictionary" situation, load a NULL dictionary + * Note 5 : Use ZSTD_CCtx_loadDictionary_advanced() to select how dictionary + * content will be interpreted. */ +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode); /*! ZSTD_CCtx_refCDict() : @@ -1050,8 +1046,11 @@ ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); * Note 1 : Prefix buffer is referenced. It must outlive compression job. * Note 2 : Referencing a prefix involves building tables, which are dependent on compression parameters. * It's a CPU-heavy operation, with non-negligible impact on latency. - * Note 3 : it's possible to alter ZSTD_p_dictMode using ZSTD_CCtx_setParameter() */ + * Note 3 : By default, the prefix is treated as raw content + * (ZSTD_dm_rawContent). Use ZSTD_CCtx_refPrefix_advanced() to alter + * dictMode. */ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize); +ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode); From 4e835720bf17a3c4cb448804a701e605d7889f5f Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Tue, 29 Aug 2017 16:18:21 -0700 Subject: [PATCH 067/248] Delay creation of ZSTDMT_CCtx --- lib/compress/zstd_compress.c | 39 +++++++++++++++------------------- lib/compress/zstdmt_compress.c | 2 +- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 990f3aa6b..4251bbb01 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -122,7 +122,7 @@ struct ZSTD_CCtx_s { /* Dictionary */ ZSTD_CDict* cdictLocal; const ZSTD_CDict* cdict; - ZSTD_prefixDict prefixDict; + ZSTD_prefixDict prefixDict; /* single-usage dictionary */ /* Multi-threading */ ZSTDMT_CCtx* mtctx; @@ -342,30 +342,16 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v case ZSTD_p_nbThreads: if (value==0) return 0; DEBUGLOG(5, " setting nbThreads : %u", value); -#ifndef ZSTD_MULTITHREAD - if (value > 1) return ERROR(parameter_unsupported); -#endif - if ((value>1) && (cctx->requestedParams.nbThreads != value)) { - if (cctx->staticSize) /* MT not compatible with static alloc */ - return ERROR(parameter_unsupported); - ZSTDMT_freeCCtx(cctx->mtctx); - cctx->requestedParams.nbThreads = 1; - cctx->mtctx = ZSTDMT_createCCtx_advanced(value, cctx->customMem); - if (cctx->mtctx == NULL) return ERROR(memory_allocation); + if (value > 1 && cctx->staticSize) { + return ERROR(parameter_unsupported); /* MT not compatible with static alloc */ } - - /* Need to initialize overlapSizeLog */ - return ZSTDMT_initializeCCtxParameters(&cctx->requestedParams, value); + return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); case ZSTD_p_jobSize: - if (cctx->requestedParams.nbThreads <= 1) return ERROR(parameter_unsupported); - assert(cctx->mtctx != NULL); return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); case ZSTD_p_overlapSizeLog: DEBUGLOG(5, " setting overlap with nbThreads == %u", cctx->requestedParams.nbThreads); - if (cctx->requestedParams.nbThreads <= 1) return ERROR(parameter_unsupported); - assert(cctx->mtctx != NULL); return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); default: return ERROR(parameter_unsupported); @@ -453,7 +439,7 @@ size_t ZSTD_CCtxParam_setParameter( return 0; case ZSTD_p_nbThreads : - if (value == 0) { return 0; } + if (value == 0) return 0; #ifndef ZSTD_MULTITHREAD if (value > 1) return ERROR(parameter_unsupported); #endif @@ -481,7 +467,8 @@ size_t ZSTD_CCtxParam_setParameter( */ size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) { - if (cctx->cdict) { return ERROR(stage_wrong); } + if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); + if (cctx->cdict) return ERROR(stage_wrong); /* Assume the compression and frame parameters are validated */ cctx->requestedParams.cParams = params->cParams; @@ -498,7 +485,6 @@ size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params CHECK_F( ZSTD_CCtx_setParameter(cctx, ZSTD_p_jobSize, params->jobSize) ); CHECK_F( ZSTD_CCtx_setParameter( cctx, ZSTD_p_overlapSizeLog, params->overlapSizeLog) ); - } /* customMem is used only for create/free params and can be ignored */ @@ -4162,11 +4148,19 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, #ifdef ZSTD_MULTITHREAD if (params.nbThreads > 1) { + if (cctx->mtctx == NULL || cctx->appliedParams.nbThreads != params.nbThreads) { + ZSTDMT_freeCCtx(cctx->mtctx); + cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbThreads, cctx->customMem); + if (cctx->mtctx == NULL) return ERROR(memory_allocation); + } + DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", params.nbThreads); + CHECK_F( ZSTDMT_initCStream_internal( cctx->mtctx, prefixDict.dict, prefixDict.dictSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); cctx->streamStage = zcss_load; + cctx->appliedParams.nbThreads = params.nbThreads; } else #endif { @@ -4178,7 +4172,8 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, /* compression stage */ #ifdef ZSTD_MULTITHREAD - if (cctx->requestedParams.nbThreads > 1) { + if (cctx->appliedParams.nbThreads > 1) { + assert(cctx->mtctx != NULL); size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); DEBUGLOG(5, "ZSTDMT_compressStream_generic : %u", (U32)flushMin); if ( ZSTD_isError(flushMin) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 41278677f..bf418df54 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -342,9 +342,9 @@ void ZSTDMT_compressChunk(void* jobDescription) } else { /* srcStart points at reloaded section */ if (!job->firstChunk) job->params.fParams.contentSizeFlag = 0; /* ensure no srcSize control */ { ZSTD_CCtx_params jobParams = job->params; - /* Force loading dictionary in "content-only" mode (no header analysis) */ size_t const forceWindowError = ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk); + /* Force loading dictionary in "content-only" mode (no header analysis) */ size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, job->srcStart, job->dictSize, ZSTD_dm_rawContent, jobParams, job->fullFrameSize); if (ZSTD_isError(initError) || ZSTD_isError(forceWindowError)) { job->cSize = initError; From 82d636b76adfcfc7f253fee4663d7a1acaab37d8 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Tue, 29 Aug 2017 18:03:06 -0700 Subject: [PATCH 068/248] Rename applyCCtxParams() --- lib/compress/zstd_compress.c | 3 ++- lib/zstd.h | 9 +++++---- tests/roundTripCrash.c | 2 +- tests/zstreamtest.c | 6 +++--- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 4251bbb01..436e73cee 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -465,7 +465,8 @@ size_t ZSTD_CCtxParam_setParameter( * * Pledged srcSize is treated as unknown. */ -size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) +size_t ZSTD_CCtx_setParametersUsingCCtxParams( + ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) { if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); if (cctx->cdict) return ERROR(stage_wrong); diff --git a/lib/zstd.h b/lib/zstd.h index 8ac564884..e062f6d2b 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -1109,7 +1109,7 @@ size_t ZSTD_compress_generic_simpleArgs ( * - ZSTD_CCtxParam_setParameter() : Push parameters one by one into an * existing ZSTD_CCtx_params structure. This is similar to * ZSTD_CCtx_setParameter(). - * - ZSTD_CCtx_applyCCtxParams() : Apply parameters to an existing CCtx. These + * - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to an existing CCtx. These * parameters will be applied to all subsequent compression jobs. * - ZSTD_compress_generic() : Do compression using the CCtx. * - ZSTD_freeCCtxParams() : Free the memory. @@ -1141,19 +1141,20 @@ ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); /*! ZSTD_CCtxParam_setParameter() : * Similar to ZSTD_CCtx_setParameter. * Set one compression parameter, selected by enum ZSTD_cParameter. - * Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_applyCCtxParams(). + * Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams(). * Note : when `value` is an enum, cast it to unsigned for proper type checking. * @result : 0, or an error code (which can be tested with ZSTD_isError()). */ ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value); -/*! ZSTD_CCtx_applyCCtxParams() : +/*! ZSTD_CCtx_setParametersUsingCCtxParams() : * Apply a set of ZSTD_CCtx_params to the compression context. * This must be done before the dictionary is loaded. * The pledgedSrcSize is treated as unknown. * Multithreading parameters are applied only if nbThreads > 1. */ -ZSTDLIB_API size_t ZSTD_CCtx_applyCCtxParams(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); +ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( + ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); /** Block functions diff --git a/tests/roundTripCrash.c b/tests/roundTripCrash.c index cb0221c58..41e5d4472 100644 --- a/tests/roundTripCrash.c +++ b/tests/roundTripCrash.c @@ -98,7 +98,7 @@ static size_t cctxParamRoundTripTest(void* resultBuff, size_t resultBuffCapacity /* Apply parameters */ - CHECK_Z( ZSTD_CCtx_applyCCtxParams(cctx, cctxParams) ); + CHECK_Z( ZSTD_CCtx_setParametersUsingCCtxParams(cctx, cctxParams) ); CHECK_Z (ZSTD_compress_generic(cctx, &outBuffer, &inBuffer, ZSTD_e_end) ); diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 5d6ef4168..f8683ac78 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1381,7 +1381,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double /* Apply parameters */ if (useOpaqueAPI) { - CHECK_Z (ZSTD_CCtx_applyCCtxParams(zc, cctxParams) ); + CHECK_Z (ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams) ); } if (FUZ_rand(&lseed) & 1) { @@ -1393,8 +1393,8 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double if (dict && dictSize) { /* test that compression parameters are rejected (correctly) after loading a non-NULL dictionary */ if (useOpaqueAPI) { - size_t const setError = ZSTD_CCtx_applyCCtxParams(zc, cctxParams); - CHECK(!ZSTD_isError(setError), "ZSTD_CCtx_applyCCtxParams should have failed"); + size_t const setError = ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams); + CHECK(!ZSTD_isError(setError), "ZSTD_CCtx_setParametersUsingCCtxParams should have failed"); } else { size_t const setError = ZSTD_CCtx_setParameter(zc, ZSTD_p_windowLog, cParams.windowLog-1); CHECK(!ZSTD_isError(setError), "ZSTD_CCtx_setParameter should have failed"); From 623e3cd40b368b48a62456a0f8f950474b969238 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Tue, 29 Aug 2017 18:04:32 -0700 Subject: [PATCH 069/248] Use ZSTD_dm_rawContent in zstdmt_compress --- lib/compress/zstdmt_compress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index bf418df54..86afe5065 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -768,7 +768,7 @@ size_t ZSTDMT_initCStream_internal( DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal); ZSTD_freeCDict(zcs->cdictLocal); zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, - ZSTD_dlm_byCopy, ZSTD_dm_auto, /* note : a loadPrefix becomes an internal CDict */ + ZSTD_dlm_byCopy, ZSTD_dm_rawContent, /* note : a loadPrefix becomes an internal CDict */ params.cParams, zcs->cMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); From a6e20e1bd7942ed6cae5382b81e11b81ea2fa701 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Tue, 29 Aug 2017 18:36:18 -0700 Subject: [PATCH 070/248] Add test for raw content starting with dict header --- lib/compress/zstd_compress.c | 1 - tests/fuzzer.c | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 436e73cee..7249f6fca 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -4174,7 +4174,6 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, /* compression stage */ #ifdef ZSTD_MULTITHREAD if (cctx->appliedParams.nbThreads > 1) { - assert(cctx->mtctx != NULL); size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); DEBUGLOG(5, "ZSTDMT_compressStream_generic : %u", (U32)flushMin); if ( ZSTD_isError(flushMin) diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 9f661175a..db4b33519 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -810,6 +810,26 @@ static int basicUnitTests(U32 seed, double compressibility) } DISPLAYLEVEL(4, "OK \n"); + DISPLAYLEVEL(4, "test%3i : Loading rawContent starting with dict header w/ ZSTD_dm_auto should fail", testNb++); + { + size_t ret; + MEM_writeLE32(dictBuffer+2, ZSTD_MAGIC_DICTIONARY); + ret = ZSTD_CCtx_loadDictionary_advanced( + cctx, (const char*)dictBuffer+2, dictSize-2, ZSTD_dlm_byRef, ZSTD_dm_auto); + if (!ZSTD_isError(ret)) goto _output_error; + } + DISPLAYLEVEL(4, "OK \n"); + + DISPLAYLEVEL(4, "test%3i : Loading rawContent starting with dict header w/ ZSTD_dm_rawContent should pass", testNb++); + { + size_t ret; + MEM_writeLE32(dictBuffer+2, ZSTD_MAGIC_DICTIONARY); + ret = ZSTD_CCtx_loadDictionary_advanced( + cctx, (const char*)dictBuffer+2, dictSize-2, ZSTD_dlm_byRef, ZSTD_dm_rawContent); + if (ZSTD_isError(ret)) goto _output_error; + } + DISPLAYLEVEL(4, "OK \n"); + ZSTD_freeCCtx(cctx); free(dictBuffer); free(samplesSizes); From ee65701720f710cf4b568a42f2917faa4b33d2be Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Tue, 29 Aug 2017 20:27:35 -0700 Subject: [PATCH 071/248] Minor fixes; remove formatting only changes --- lib/common/zstd_internal.h | 16 ++++++++-------- lib/compress/zstd_compress.c | 31 ++++++++++++++----------------- tests/fuzzer.c | 4 ++-- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 6097f8e6f..19c0a6261 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -352,12 +352,10 @@ void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx); * expects params to be valid. * must receive dict, or cdict, or none, but not both. * @return : 0, or an error code */ -size_t ZSTD_initCStream_internal( - ZSTD_CStream* zcs, - const void* dict, size_t dictSize, - const ZSTD_CDict* cdict, - ZSTD_CCtx_params params, - unsigned long long pledgedSrcSize); +size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + const ZSTD_CDict* cdict, + ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); /*! ZSTD_compressStream_generic() : * Private use only. To be called from zstdmt_compress.c in single-thread mode. */ @@ -370,14 +368,16 @@ size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, * as the name implies */ ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict); -/* INTERNAL */ +/* ZSTD_compressBegin_advanced_internal() : + * Private use only. To be called from zstdmt_compress.c. */ size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); -/* INTERNAL */ +/* ZSTD_compress_advanced_internal() : + * Private use only. To be called from zstdmt_compress.c. */ size_t ZSTD_compress_advanced_internal(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 7249f6fca..206e0976a 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -516,8 +516,7 @@ size_t ZSTD_CCtx_loadDictionary_advanced( ZSTD_getCParamsFromCCtxParams(cctx->requestedParams, 0, dictSize); cctx->cdictLocal = ZSTD_createCDict_advanced( dict, dictSize, - dictLoadMethod, - dictMode, + dictLoadMethod, dictMode, cParams, cctx->customMem); cctx->cdict = cctx->cdictLocal; if (cctx->cdictLocal == NULL) @@ -564,7 +563,6 @@ size_t ZSTD_CCtx_refPrefix_advanced( return 0; } - static void ZSTD_startNewCompression(ZSTD_CCtx* cctx) { cctx->streamStage = zcss_init; @@ -785,7 +783,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, if (crp == ZSTDcrp_continue) { if (ZSTD_equivalentParams(params, zc->appliedParams)) { - DEBUGLOG(5, "ZSTD_equivalentCParams()==1"); + DEBUGLOG(5, "ZSTD_equivalentParams()==1"); zc->entropy->hufCTable_repeatMode = HUF_repeat_none; zc->entropy->offcode_repeatMode = FSE_repeat_none; zc->entropy->matchlength_repeatMode = FSE_repeat_none; @@ -3122,7 +3120,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */ if (frame && (cctx->stage==ZSTDcs_init)) { - fhSize = ZSTD_writeFrameHeader(dst, dstCapacity,cctx->appliedParams, + fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, cctx->pledgedSrcSizePlusOne-1, cctx->dictID); if (ZSTD_isError(fhSize)) return fhSize; dstCapacity -= fhSize; @@ -3582,7 +3580,7 @@ size_t ZSTD_estimateCDictSize_advanced( size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) { ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); - return ZSTD_estimateCDictSize_advanced(dictSize, cParams, 0); + return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); } size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) @@ -3624,6 +3622,7 @@ static size_t ZSTD_initCDict_internal( cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered) ); } + return 0; } @@ -3637,6 +3636,7 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem); + if (!cdict || !cctx) { ZSTD_free(cdict, customMem); ZSTD_freeCCtx(cctx); @@ -3650,6 +3650,7 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, ZSTD_freeCDict(cdict); return NULL; } + return cdict; } } @@ -3822,11 +3823,10 @@ size_t ZSTD_CStreamOutSize(void) return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; } -static size_t ZSTD_resetCStream_internal( - ZSTD_CStream* zcs, - const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, - const ZSTD_CDict* cdict, - const ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) +static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, + const ZSTD_CDict* cdict, + const ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) { DEBUGLOG(4, "ZSTD_resetCStream_internal"); /* params are supposed to be fully validated at this point */ @@ -3862,9 +3862,8 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) * Assumption 1 : params are valid * Assumption 2 : either dict, or cdict, is defined, not both */ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, - const void* dict, size_t dictSize, - const ZSTD_CDict* cdict, - ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) + const void* dict, size_t dictSize, const ZSTD_CDict* cdict, + ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) { assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ @@ -3876,8 +3875,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, return ERROR(memory_allocation); } ZSTD_freeCDict(zcs->cdictLocal); - zcs->cdictLocal = ZSTD_createCDict_advanced( - dict, dictSize, + zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dm_auto, params.cParams, zcs->customMem); zcs->cdict = zcs->cdictLocal; @@ -4156,7 +4154,6 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, } DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", params.nbThreads); - CHECK_F( ZSTDMT_initCStream_internal( cctx->mtctx, prefixDict.dict, prefixDict.dictSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); diff --git a/tests/fuzzer.c b/tests/fuzzer.c index db4b33519..439ab39d9 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -813,7 +813,7 @@ static int basicUnitTests(U32 seed, double compressibility) DISPLAYLEVEL(4, "test%3i : Loading rawContent starting with dict header w/ ZSTD_dm_auto should fail", testNb++); { size_t ret; - MEM_writeLE32(dictBuffer+2, ZSTD_MAGIC_DICTIONARY); + MEM_writeLE32((char*)dictBuffer+2, ZSTD_MAGIC_DICTIONARY); ret = ZSTD_CCtx_loadDictionary_advanced( cctx, (const char*)dictBuffer+2, dictSize-2, ZSTD_dlm_byRef, ZSTD_dm_auto); if (!ZSTD_isError(ret)) goto _output_error; @@ -823,7 +823,7 @@ static int basicUnitTests(U32 seed, double compressibility) DISPLAYLEVEL(4, "test%3i : Loading rawContent starting with dict header w/ ZSTD_dm_rawContent should pass", testNb++); { size_t ret; - MEM_writeLE32(dictBuffer+2, ZSTD_MAGIC_DICTIONARY); + MEM_writeLE32((char*)dictBuffer+2, ZSTD_MAGIC_DICTIONARY); ret = ZSTD_CCtx_loadDictionary_advanced( cctx, (const char*)dictBuffer+2, dictSize-2, ZSTD_dlm_byRef, ZSTD_dm_rawContent); if (ZSTD_isError(ret)) goto _output_error; From 90a31bfa162ce0aaac9f3645ab553bbc417b5bc3 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Wed, 30 Aug 2017 14:36:54 -0700 Subject: [PATCH 072/248] Pass dictMode to ZSTDMT_initCStream; fix nits - Return error code in estimate{CCtx,CStream}Size functions --- lib/compress/zstd_compress.c | 45 +++++++++++++++------------------- lib/compress/zstdmt_compress.c | 15 ++++++------ lib/zstd.h | 8 +++--- tests/zstreamtest.c | 22 +++++++++++++++++ 4 files changed, 54 insertions(+), 36 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 206e0976a..5adeb480b 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -233,7 +233,7 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( ZSTD_compressionParameters cParams) { ZSTD_CCtx_params cctxParams; - memset(&cctxParams, 0, sizeof(ZSTD_CCtx_params)); + memset(&cctxParams, 0, sizeof(cctxParams)); cctxParams.cParams = cParams; cctxParams.compressionLevel = ZSTD_CLEVEL_CUSTOM; return cctxParams; @@ -271,7 +271,7 @@ size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params) size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, int compressionLevel) { if (!cctxParams) { return ERROR(GENERIC); } - memset(cctxParams, 0, sizeof(ZSTD_CCtx_params)); + memset(cctxParams, 0, sizeof(*cctxParams)); cctxParams->compressionLevel = compressionLevel; return 0; } @@ -280,7 +280,7 @@ size_t ZSTD_initCCtxParams_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameter { if (!cctxParams) { return ERROR(GENERIC); } CHECK_F( ZSTD_checkCParams(params.cParams) ); - memset(cctxParams, 0, sizeof(ZSTD_CCtx_params)); + memset(cctxParams, 0, sizeof(*cctxParams)); cctxParams->cParams = params.cParams; cctxParams->fParams = params.fParams; cctxParams->compressionLevel = ZSTD_CLEVEL_CUSTOM; @@ -543,7 +543,7 @@ size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) { if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); cctx->cdict = cdict; - memset(&cctx->prefixDict, 0, sizeof(ZSTD_prefixDict)); /* exclusive */ + memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* exclusive */ return 0; } @@ -657,9 +657,7 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params) { /* Estimate CCtx size is supported for single-threaded compression only. */ - if (params->nbThreads > 1) { - return 0; - } + if (params->nbThreads > 1) { return ERROR(GENERIC); } { ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams(*params, 0, 0); size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); @@ -701,9 +699,7 @@ size_t ZSTD_estimateCCtxSize(int compressionLevel) size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params) { - if (params->nbThreads > 1) { - return 0; - } + if (params->nbThreads > 1) { return ERROR(GENERIC); } { size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced_usingCCtxParams(params); size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog); size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize; @@ -3171,7 +3167,7 @@ size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) { - ZSTD_compressionParameters cParams = + ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams(cctx->appliedParams, 0, 0); return MIN (ZSTD_BLOCKSIZE_MAX, 1 << cParams.windowLog); } @@ -3413,7 +3409,7 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params cctxParams = + ZSTD_CCtx_params const cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); return ZSTD_compressBegin_advanced_internal(cctx, dict, dictSize, ZSTD_dm_auto, cctxParams, @@ -3423,7 +3419,7 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) { ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); - ZSTD_CCtx_params cctxParams = + ZSTD_CCtx_params const cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL, cctxParams, 0, ZSTDb_not_buffered); @@ -3505,7 +3501,7 @@ static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, const void* dict,size_t dictSize, ZSTD_parameters params) { - ZSTD_CCtx_params cctxParams = + ZSTD_CCtx_params const cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, @@ -3611,10 +3607,7 @@ static size_t ZSTD_initCDict_internal( } cdict->dictContentSize = dictSize; - { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, - 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */ - ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams; - cctxParams.fParams = fParams; + { ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams; cctxParams.cParams = cParams; CHECK_F( ZSTD_compressBegin_internal(cdict->refContext, cdict->dictContent, dictSize, dictMode, @@ -3923,7 +3916,7 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params cctxParams = + ZSTD_CCtx_params const cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); CHECK_F( ZSTD_checkCParams(params.cParams) ); return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, pledgedSrcSize); @@ -3932,7 +3925,7 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) { ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); - ZSTD_CCtx_params cctxParams = + ZSTD_CCtx_params const cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, 0); } @@ -3940,9 +3933,9 @@ size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t di size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize) { ZSTD_CCtx_params cctxParams; - ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0); - params.fParams.contentSizeFlag = (pledgedSrcSize>0); + ZSTD_parameters const params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0); cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); + cctxParams.fParams.contentSizeFlag = (pledgedSrcSize>0); return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, cctxParams, pledgedSrcSize); } @@ -4122,7 +4115,8 @@ size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuf * must receive dict, or cdict, or none, but not both. * @return : 0, or an error code */ size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, - const void* dict, size_t dictSize, const ZSTD_CDict* cdict, + const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, + const ZSTD_CDict* cdict, ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); @@ -4142,7 +4136,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, ZSTD_CCtx_params params = cctx->requestedParams; params.cParams = ZSTD_getCParamsFromCCtxParams( cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); - memset(&cctx->prefixDict, 0, sizeof(ZSTD_prefixDict)); /* single usage */ + memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ #ifdef ZSTD_MULTITHREAD @@ -4155,7 +4149,8 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", params.nbThreads); CHECK_F( ZSTDMT_initCStream_internal( - cctx->mtctx, prefixDict.dict, prefixDict.dictSize, + cctx->mtctx, + prefixDict.dict, prefixDict.dictSize, ZSTD_dm_rawContent, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); cctx->streamStage = zcss_load; cctx->appliedParams.nbThreads = params.nbThreads; diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 86afe5065..166f99d72 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -191,7 +191,7 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf) static ZSTD_CCtx_params ZSTDMT_makeJobCCtxParams(ZSTD_CCtx_params const params) { ZSTD_CCtx_params jobParams; - memset(&jobParams, 0, sizeof(ZSTD_CCtx_params)); + memset(&jobParams, 0, sizeof(jobParams)); jobParams.cParams = params.cParams; jobParams.fParams = params.fParams; @@ -737,7 +737,8 @@ static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs) } size_t ZSTDMT_initCStream_internal( - ZSTDMT_CCtx* zcs, const void* dict, size_t dictSize, + ZSTDMT_CCtx* zcs, + const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, const ZSTD_CDict* cdict, ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) { @@ -768,7 +769,7 @@ size_t ZSTDMT_initCStream_internal( DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal); ZSTD_freeCDict(zcs->cdictLocal); zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, - ZSTD_dlm_byCopy, ZSTD_dm_rawContent, /* note : a loadPrefix becomes an internal CDict */ + ZSTD_dlm_byCopy, dictMode, /* note : a loadPrefix becomes an internal CDict */ params.cParams, zcs->cMem); zcs->cdict = zcs->cdictLocal; if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); @@ -807,7 +808,7 @@ size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx, DEBUGLOG(5, "ZSTDMT_initCStream_advanced"); cctxParams.cParams = params.cParams; cctxParams.fParams = params.fParams; - return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, NULL, + return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, ZSTD_dm_auto, NULL, cctxParams, pledgedSrcSize); } @@ -820,7 +821,7 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx, cctxParams.cParams = ZSTD_getCParamsFromCDict(cdict); cctxParams.fParams = fParams; if (cdict==NULL) return ERROR(dictionary_wrong); /* method incompatible with NULL cdict */ - return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, cdict, + return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, ZSTD_dm_auto, cdict, cctxParams, pledgedSrcSize); } @@ -831,7 +832,7 @@ size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* zcs, unsigned long long pledgedSrcSize) { if (zcs->params.nbThreads==1) return ZSTD_resetCStream(zcs->cctxPool->cctx[0], pledgedSrcSize); - return ZSTDMT_initCStream_internal(zcs, NULL, 0, 0, zcs->params, + return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, 0, zcs->params, pledgedSrcSize); } @@ -840,7 +841,7 @@ size_t ZSTDMT_initCStream(ZSTDMT_CCtx* zcs, int compressionLevel) { ZSTD_CCtx_params cctxParams = zcs->params; cctxParams.cParams = params.cParams; cctxParams.fParams = params.fParams; - return ZSTDMT_initCStream_internal(zcs, NULL, 0, NULL, cctxParams, 0); + return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, NULL, cctxParams, 0); } diff --git a/lib/zstd.h b/lib/zstd.h index e062f6d2b..c11964408 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -498,7 +498,7 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); * It will also consider src size to be arbitrarily "large", which is worst case. * If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced_usingCParams() can provide a tighter estimation. * ZSTD_estimateCCtxSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - * ZSTD_estimateCCtxSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return 0 if ZSTD_p_nbThreads is set to a value > 1. + * ZSTD_estimateCCtxSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1. * Note : CCtx estimation is only correct for single-threaded compression */ ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel); ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced_usingCParams(ZSTD_compressionParameters cParams); @@ -510,7 +510,7 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); * It will also consider src size to be arbitrarily "large", which is worst case. * If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced_usingCParams() can provide a tighter estimation. * ZSTD_estimateCStreamSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - * ZSTD_estimateCStreamSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return 0 if ZSTD_p_nbThreads is set to a value > 1. + * ZSTD_estimateCStreamSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1. * Note : CStream estimation is only correct for single-threaded compression. * ZSTD_DStream memory budget depends on window Size. * This information can be passed manually, using ZSTD_estimateDStreamSize, @@ -727,9 +727,9 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize); ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); ZSTDLIB_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */ ZSTDLIB_API size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); /**< pledgedSrcSize must be correct, a size of 0 means unknown. for a frame size of 0 use initCStream_advanced */ -ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. */ +ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. Note: dict is loaded with ZSTD_dm_auto (treated as a full zstd dictionary if it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.*/ ZSTDLIB_API size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize, - ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize is optional and can be 0 (meaning unknown). note: if the contentSizeFlag is set, pledgedSrcSize == 0 means the source size is actually 0 */ + ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize is optional and can be 0 (meaning unknown). note: if the contentSizeFlag is set, pledgedSrcSize == 0 means the source size is actually 0. dict is loaded with ZSTD_dm_auto and ZSTD_dlm_byCopy. */ ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); /**< note : cdict will just be referenced, and must outlive compression session */ ZSTDLIB_API size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize); /**< same as ZSTD_initCStream_usingCDict(), with control over frame parameters */ diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index f8683ac78..8be6a5910 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -149,6 +149,8 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo U32 testNb = 1; ZSTD_CStream* zc = ZSTD_createCStream_advanced(customMem); ZSTD_DStream* zd = ZSTD_createDStream_advanced(customMem); + ZSTDMT_CCtx* mtctx = ZSTDMT_createCCtx(2); + ZSTD_inBuffer inBuff, inBuff2; ZSTD_outBuffer outBuff; buffer_t dictionary = g_nullBuffer; @@ -605,6 +607,25 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != ZSTD_CONTENTSIZE_UNKNOWN) goto _output_error; DISPLAYLEVEL(3, "OK \n"); + /* Basic multithreading compression test */ + DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads : ", testNb++, COMPRESSIBLE_NOISE_LENGTH); + { ZSTD_parameters const params = ZSTD_getParams(1, 0, 0); + size_t const r = ZSTDMT_initCStream_advanced(mtctx, CNBuffer, dictSize, params, CNBufferSize); + if (ZSTD_isError(r)) goto _output_error; } + outBuff.dst = (char*)(compressedBuffer); + outBuff.size = compressedBufferSize; + outBuff.pos = 0; + inBuff.src = CNBuffer; + inBuff.size = CNBufferSize; + inBuff.pos = 0; + { size_t const r = ZSTDMT_compressStream_generic(mtctx, &outBuff, &inBuff, ZSTD_e_end); + if (ZSTD_isError(r)) goto _output_error; } + if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */ + { size_t const r = ZSTDMT_endStream(mtctx, &outBuff); + if (r != 0) goto _output_error; } /* error, or some data not flushed */ + DISPLAYLEVEL(3, "OK \n"); + + /* Overlen overwriting window data bug */ DISPLAYLEVEL(3, "test%3i : wildcopy doesn't overwrite potential match data : ", testNb++); { /* This test has a window size of 1024 bytes and consists of 3 blocks: @@ -643,6 +664,7 @@ _end: FUZ_freeDictionary(dictionary); ZSTD_freeCStream(zc); ZSTD_freeDStream(zd); + ZSTDMT_freeCCtx(mtctx); free(CNBuffer); free(compressedBuffer); free(decodedBuffer); From 9023898f1e2f51a2bc31367b11eb382e6e724496 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 30 Aug 2017 17:44:12 -0700 Subject: [PATCH 073/248] updated NEWS --- NEWS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NEWS b/NEWS index 59687532f..ef7dc71b4 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,8 @@ +v1.3.2 +fix : a rare compression bug when compression generates very large distances (only possible at --ultra -22) +build: better compatibility with reproducible builds, by Bernhard M. Wiedemann (@bmwiedemann) (#818) +changed : examples license changed to BSD + GPLv2 + v1.3.1 New license : BSD + GPLv2 perf: substantially decreased memory usage in Multi-threading mode, thanks to reports by Tino Reichardt (@mcmilk) From e9dc204f42426f9f92459216875c5171ddd98d23 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 31 Aug 2017 11:24:54 -0700 Subject: [PATCH 074/248] fixed a bunch of headers after license change (#825) --- Makefile | 8 ++++---- build/cmake/CMakeLists.txt | 6 +++--- build/cmake/contrib/CMakeLists.txt | 14 +++++--------- build/cmake/contrib/gen_html/CMakeLists.txt | 13 +++++-------- build/cmake/contrib/pzstd/CMakeLists.txt | 13 +++++-------- contrib/gen_html/Makefile | 10 +++++----- contrib/long_distance_matching/Makefile | 13 ++++++------- contrib/pzstd/ErrorHolder.h | 8 ++++---- contrib/pzstd/Logging.h | 8 ++++---- contrib/pzstd/Options.h | 8 ++++---- contrib/pzstd/SkippableFrame.cpp | 8 ++++---- contrib/pzstd/SkippableFrame.h | 8 ++++---- contrib/pzstd/main.cpp | 8 ++++---- contrib/pzstd/test/RoundTrip.h | 8 ++++---- contrib/pzstd/utils/Likely.h | 8 ++++---- contrib/pzstd/utils/ScopeGuard.h | 8 ++++---- contrib/pzstd/utils/ThreadPool.h | 8 ++++---- contrib/pzstd/utils/test/BufferTest.cpp | 8 ++++---- contrib/pzstd/utils/test/RangeTest.cpp | 8 ++++---- contrib/pzstd/utils/test/ResourcePoolTest.cpp | 8 ++++---- contrib/pzstd/utils/test/ScopeGuardTest.cpp | 8 ++++---- contrib/pzstd/utils/test/ThreadPoolTest.cpp | 8 ++++---- contrib/seekable_format/examples/Makefile | 6 +++--- examples/Makefile | 6 +++--- lib/common/threading.c | 12 ++++++------ lib/dll/example/Makefile | 10 +++++----- tests/fuzz/fuzz_helpers.h | 8 ++++---- tests/fuzz/simple_decompress.c | 10 +++++----- tests/gzip/Makefile | 10 +++++----- 29 files changed, 124 insertions(+), 135 deletions(-) diff --git a/Makefile b/Makefile index a72f99fcb..423d0a18b 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ # ################################################################ -# Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +# Copyright (c) 2015-present, Yann Collet, Facebook, Inc. # All rights reserved. # -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. +# 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). # ################################################################ PRGDIR = programs diff --git a/build/cmake/CMakeLists.txt b/build/cmake/CMakeLists.txt index 6e30c5325..8e8824e7c 100644 --- a/build/cmake/CMakeLists.txt +++ b/build/cmake/CMakeLists.txt @@ -2,9 +2,9 @@ # Copyright (c) 2016-present, Yann Collet, Facebook, Inc. # All rights reserved. # -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. +# 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). # ################################################################ PROJECT(zstd) diff --git a/build/cmake/contrib/CMakeLists.txt b/build/cmake/contrib/CMakeLists.txt index c7d97aa95..8c7bc78ae 100644 --- a/build/cmake/contrib/CMakeLists.txt +++ b/build/cmake/contrib/CMakeLists.txt @@ -1,17 +1,13 @@ # ################################################################ -# * Copyright (c) 2015-present, Yann Collet, Facebook, Inc. -# * All rights reserved. -# * -# * This source code is licensed under the BSD-style license found in the -# * LICENSE file in the root directory of this source tree. An additional grant -# * of patent rights can be found in the PATENTS file in the same directory. +# Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +# All rights reserved. # -# You can contact the author at : -# - zstd homepage : http://www.zstd.net/ +# 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). # ################################################################ PROJECT(contrib) ADD_SUBDIRECTORY(pzstd) ADD_SUBDIRECTORY(gen_html) - diff --git a/build/cmake/contrib/gen_html/CMakeLists.txt b/build/cmake/contrib/gen_html/CMakeLists.txt index c10c62b54..01d190672 100644 --- a/build/cmake/contrib/gen_html/CMakeLists.txt +++ b/build/cmake/contrib/gen_html/CMakeLists.txt @@ -1,13 +1,10 @@ # ################################################################ -# * Copyright (c) 2015-present, Yann Collet, Facebook, Inc. -# * All rights reserved. -# * -# * This source code is licensed under the BSD-style license found in the -# * LICENSE file in the root directory of this source tree. An additional grant -# * of patent rights can be found in the PATENTS file in the same directory. +# Copyright (c) 2015-present, Yann Collet, Facebook, Inc. +# All rights reserved. # -# You can contact the author at : -# - zstd homepage : http://www.zstd.net/ +# 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). # ################################################################ PROJECT(gen_html) diff --git a/build/cmake/contrib/pzstd/CMakeLists.txt b/build/cmake/contrib/pzstd/CMakeLists.txt index 71def02cd..e6db47198 100644 --- a/build/cmake/contrib/pzstd/CMakeLists.txt +++ b/build/cmake/contrib/pzstd/CMakeLists.txt @@ -1,13 +1,10 @@ # ################################################################ -# * Copyright (c) 2015-present, Yann Collet, Facebook, Inc. -# * All rights reserved. -# * -# * This source code is licensed under the BSD-style license found in the -# * LICENSE file in the root directory of this source tree. An additional grant -# * of patent rights can be found in the PATENTS file in the same directory. +# Copyright (c) 2016-present, Facebook, Inc. +# All rights reserved. # -# You can contact the author at : -# - zstd homepage : http://www.zstd.net/ +# 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). # ################################################################ PROJECT(pzstd) diff --git a/contrib/gen_html/Makefile b/contrib/gen_html/Makefile index ea68b11fc..d9b32e351 100644 --- a/contrib/gen_html/Makefile +++ b/contrib/gen_html/Makefile @@ -1,11 +1,11 @@ -# ########################################################################## +# ################################################################ # Copyright (c) 2016-present, Facebook, Inc. # All rights reserved. # -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. -# ########################################################################## +# 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). +# ################################################################ CFLAGS ?= -O3 CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wstrict-aliasing=1 -Wswitch-enum -Wno-comment diff --git a/contrib/long_distance_matching/Makefile b/contrib/long_distance_matching/Makefile index 4193cb323..6ed1fab45 100644 --- a/contrib/long_distance_matching/Makefile +++ b/contrib/long_distance_matching/Makefile @@ -1,10 +1,10 @@ # ################################################################ -# Copyright (c) 2016-present, Facebook, Inc. +# Copyright (c) 2017-present, Facebook, Inc. # All rights reserved. # -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. +# 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). # ################################################################ # This Makefile presumes libzstd is installed, using `sudo make install` @@ -25,8 +25,8 @@ LDFLAGS += -lzstd default: all -all: ldm - +all: ldm + ldm: ldm_common.c ldm.c main.c $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@ @@ -34,4 +34,3 @@ clean: @rm -f core *.o tmp* result* *.ldm *.ldm.dec \ ldm @echo Cleaning completed - diff --git a/contrib/pzstd/ErrorHolder.h b/contrib/pzstd/ErrorHolder.h index 188badcad..829651c59 100644 --- a/contrib/pzstd/ErrorHolder.h +++ b/contrib/pzstd/ErrorHolder.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #pragma once diff --git a/contrib/pzstd/Logging.h b/contrib/pzstd/Logging.h index 76c982ab2..16a63932c 100644 --- a/contrib/pzstd/Logging.h +++ b/contrib/pzstd/Logging.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #pragma once diff --git a/contrib/pzstd/Options.h b/contrib/pzstd/Options.h index d58de017e..f4f2aaa49 100644 --- a/contrib/pzstd/Options.h +++ b/contrib/pzstd/Options.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #pragma once diff --git a/contrib/pzstd/SkippableFrame.cpp b/contrib/pzstd/SkippableFrame.cpp index 5dc95e5ab..769866dfc 100644 --- a/contrib/pzstd/SkippableFrame.cpp +++ b/contrib/pzstd/SkippableFrame.cpp @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include "SkippableFrame.h" #include "mem.h" diff --git a/contrib/pzstd/SkippableFrame.h b/contrib/pzstd/SkippableFrame.h index 9dc95c1f5..60deed040 100644 --- a/contrib/pzstd/SkippableFrame.h +++ b/contrib/pzstd/SkippableFrame.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #pragma once diff --git a/contrib/pzstd/main.cpp b/contrib/pzstd/main.cpp index 7d8dbfbcf..b93f043b1 100644 --- a/contrib/pzstd/main.cpp +++ b/contrib/pzstd/main.cpp @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include "ErrorHolder.h" #include "Options.h" diff --git a/contrib/pzstd/test/RoundTrip.h b/contrib/pzstd/test/RoundTrip.h index 8b9088459..c6364ecb4 100644 --- a/contrib/pzstd/test/RoundTrip.h +++ b/contrib/pzstd/test/RoundTrip.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #pragma once diff --git a/contrib/pzstd/utils/Likely.h b/contrib/pzstd/utils/Likely.h index c8ea102b1..7cea8da27 100644 --- a/contrib/pzstd/utils/Likely.h +++ b/contrib/pzstd/utils/Likely.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ /** diff --git a/contrib/pzstd/utils/ScopeGuard.h b/contrib/pzstd/utils/ScopeGuard.h index 5a333e0ab..31768f43d 100644 --- a/contrib/pzstd/utils/ScopeGuard.h +++ b/contrib/pzstd/utils/ScopeGuard.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #pragma once diff --git a/contrib/pzstd/utils/ThreadPool.h b/contrib/pzstd/utils/ThreadPool.h index 99b3ecfa5..8ece8e0da 100644 --- a/contrib/pzstd/utils/ThreadPool.h +++ b/contrib/pzstd/utils/ThreadPool.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #pragma once diff --git a/contrib/pzstd/utils/test/BufferTest.cpp b/contrib/pzstd/utils/test/BufferTest.cpp index 66ec961e2..fbba74e82 100644 --- a/contrib/pzstd/utils/test/BufferTest.cpp +++ b/contrib/pzstd/utils/test/BufferTest.cpp @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include "utils/Buffer.h" #include "utils/Range.h" diff --git a/contrib/pzstd/utils/test/RangeTest.cpp b/contrib/pzstd/utils/test/RangeTest.cpp index c761c8aff..755b50fa6 100644 --- a/contrib/pzstd/utils/test/RangeTest.cpp +++ b/contrib/pzstd/utils/test/RangeTest.cpp @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include "utils/Range.h" diff --git a/contrib/pzstd/utils/test/ResourcePoolTest.cpp b/contrib/pzstd/utils/test/ResourcePoolTest.cpp index a6a86b345..6fe145180 100644 --- a/contrib/pzstd/utils/test/ResourcePoolTest.cpp +++ b/contrib/pzstd/utils/test/ResourcePoolTest.cpp @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include "utils/ResourcePool.h" diff --git a/contrib/pzstd/utils/test/ScopeGuardTest.cpp b/contrib/pzstd/utils/test/ScopeGuardTest.cpp index 0c4dc0357..7bc624da7 100644 --- a/contrib/pzstd/utils/test/ScopeGuardTest.cpp +++ b/contrib/pzstd/utils/test/ScopeGuardTest.cpp @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include "utils/ScopeGuard.h" diff --git a/contrib/pzstd/utils/test/ThreadPoolTest.cpp b/contrib/pzstd/utils/test/ThreadPoolTest.cpp index 89085afd4..703fd4c9c 100644 --- a/contrib/pzstd/utils/test/ThreadPoolTest.cpp +++ b/contrib/pzstd/utils/test/ThreadPoolTest.cpp @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include "utils/ThreadPool.h" diff --git a/contrib/seekable_format/examples/Makefile b/contrib/seekable_format/examples/Makefile index 625e1fcc8..1847aa7e7 100644 --- a/contrib/seekable_format/examples/Makefile +++ b/contrib/seekable_format/examples/Makefile @@ -2,9 +2,9 @@ # Copyright (c) 2017-present, Facebook, Inc. # All rights reserved. # -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. +# 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). # ################################################################ # This Makefile presumes libzstd is built, using `make` in / or /lib/ diff --git a/examples/Makefile b/examples/Makefile index e279a537d..d1dbc56db 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -2,9 +2,9 @@ # Copyright (c) 2016-present, Yann Collet, Facebook, Inc. # All rights reserved. # -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. +# 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). # ################################################################ # This Makefile presumes libzstd is installed, using `sudo make install` diff --git a/lib/common/threading.c b/lib/common/threading.c index 141376c56..4e47b6b91 100644 --- a/lib/common/threading.c +++ b/lib/common/threading.c @@ -2,9 +2,9 @@ * Copyright (c) 2016 Tino Reichardt * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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 can contact the author at: * - zstdmt source repository: https://github.com/mcmilk/zstdmt @@ -15,9 +15,9 @@ */ /* When ZSTD_MULTITHREAD is not defined, this file would become an empty translation unit. -* Include some ISO C header code to prevent this and portably avoid related warnings. -* (Visual C++: C4206 / GCC: -Wpedantic / Clang: -Wempty-translation-unit) -*/ + * Include some ISO C header code to prevent this and portably avoid related warnings. + * (Visual C++: C4206 / GCC: -Wpedantic / Clang: -Wempty-translation-unit) + */ #include diff --git a/lib/dll/example/Makefile b/lib/dll/example/Makefile index 36041a0e3..45d0db3cd 100644 --- a/lib/dll/example/Makefile +++ b/lib/dll/example/Makefile @@ -1,11 +1,11 @@ -# ########################################################################## +# ################################################################ # Copyright (c) 2016-present, Yann Collet, Facebook, Inc. # All rights reserved. # -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. -# ########################################################################## +# 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). +# ################################################################ VOID := /dev/null ZSTDDIR := ../include diff --git a/tests/fuzz/fuzz_helpers.h b/tests/fuzz/fuzz_helpers.h index 5f07fa4de..f7cc3d5bb 100644 --- a/tests/fuzz/fuzz_helpers.h +++ b/tests/fuzz/fuzz_helpers.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ /** diff --git a/tests/fuzz/simple_decompress.c b/tests/fuzz/simple_decompress.c index c22ad7c53..a225b9dc7 100644 --- a/tests/fuzz/simple_decompress.c +++ b/tests/fuzz/simple_decompress.c @@ -1,10 +1,10 @@ -/** - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +/* + * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ /** diff --git a/tests/gzip/Makefile b/tests/gzip/Makefile index b02fb693f..40a0ba97d 100644 --- a/tests/gzip/Makefile +++ b/tests/gzip/Makefile @@ -1,10 +1,10 @@ # ################################################################ -# Copyright (c) 2017-present, Yann Collet, Facebook, Inc. +# Copyright (c) 2017-present, Facebook, Inc. # All rights reserved. # -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. +# 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). # ################################################################ PRGDIR = ../../programs @@ -12,7 +12,7 @@ VOID = /dev/null export PATH := .:$(PATH) .PHONY: all -#all: test-gzip-env +#all: test-gzip-env all: test-helin-segv test-hufts test-keep test-list test-memcpy-abuse test-mixed all: test-null-suffix-clobber test-stdin test-trailing-nul test-unpack-invalid all: test-zdiff test-zgrep-context test-zgrep-f test-zgrep-signal test-znew-k test-z-suffix From e21384fffb279a1201d3895a4c81dbfd0d44e2a2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 31 Aug 2017 12:11:57 -0700 Subject: [PATCH 075/248] fixed more file headers after license change (#825) --- NEWS | 3 ++- build/cmake/programs/CMakeLists.txt | 13 +++++-------- contrib/adaptive-compression/datagencli.c | 8 ++++---- contrib/gen_html/gen_html.cpp | 6 +++--- contrib/pzstd/Makefile | 10 +++++----- contrib/pzstd/Pzstd.h | 8 ++++---- contrib/pzstd/test/PzstdTest.cpp | 8 ++++---- contrib/pzstd/test/RoundTripTest.cpp | 8 ++++---- contrib/pzstd/utils/Buffer.h | 8 ++++---- contrib/pzstd/utils/FileSystem.h | 8 ++++---- contrib/pzstd/utils/Range.h | 8 ++++---- contrib/pzstd/utils/ResourcePool.h | 8 ++++---- contrib/pzstd/utils/WorkQueue.h | 8 ++++---- contrib/pzstd/utils/test/WorkQueueTest.cpp | 8 ++++---- doc/educational_decoder/harness.c | 6 +++--- doc/educational_decoder/zstd_decompress.h | 8 ++++---- lib/common/threading.h | 6 +++--- tests/fuzz/Makefile | 12 +++++------- tests/fuzz/fuzz.h | 8 ++++---- tests/fuzz/regression_driver.c | 8 ++++---- tests/fuzz/simple_round_trip.c | 8 ++++---- tests/fuzz/stream_decompress.c | 10 +++++----- tests/fuzz/stream_round_trip.c | 8 ++++---- 23 files changed, 91 insertions(+), 95 deletions(-) diff --git a/NEWS b/NEWS index ef7dc71b4..3ee7d0c32 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,8 @@ v1.3.2 +license : changed /examples license to BSD + GPLv2 +license : fix a few header files to reflect new license (#825) fix : a rare compression bug when compression generates very large distances (only possible at --ultra -22) build: better compatibility with reproducible builds, by Bernhard M. Wiedemann (@bmwiedemann) (#818) -changed : examples license changed to BSD + GPLv2 v1.3.1 New license : BSD + GPLv2 diff --git a/build/cmake/programs/CMakeLists.txt b/build/cmake/programs/CMakeLists.txt index 13dd31572..9251fd295 100644 --- a/build/cmake/programs/CMakeLists.txt +++ b/build/cmake/programs/CMakeLists.txt @@ -1,13 +1,10 @@ # ################################################################ -# * Copyright (c) 2015-present, Yann Collet, Facebook, Inc. -# * All rights reserved. -# * -# * This source code is licensed under the BSD-style license found in the -# * LICENSE file in the root directory of this source tree. An additional grant -# * of patent rights can be found in the PATENTS file in the same directory. +# Copyright (c) 2015-present, Yann Collet, Facebook, Inc. +# All rights reserved. # -# You can contact the author at : -# - zstd homepage : http://www.zstd.net/ +# 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). # ################################################################ PROJECT(programs) diff --git a/contrib/adaptive-compression/datagencli.c b/contrib/adaptive-compression/datagencli.c index 8a81939d1..bf9601f20 100644 --- a/contrib/adaptive-compression/datagencli.c +++ b/contrib/adaptive-compression/datagencli.c @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ diff --git a/contrib/gen_html/gen_html.cpp b/contrib/gen_html/gen_html.cpp index e5261c086..90d5b21a3 100644 --- a/contrib/gen_html/gen_html.cpp +++ b/contrib/gen_html/gen_html.cpp @@ -2,9 +2,9 @@ * Copyright (c) 2016-present, Przemyslaw Skibinski, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include diff --git a/contrib/pzstd/Makefile b/contrib/pzstd/Makefile index cec6959e6..40531e216 100644 --- a/contrib/pzstd/Makefile +++ b/contrib/pzstd/Makefile @@ -1,11 +1,11 @@ -# ########################################################################## +# ################################################################ # Copyright (c) 2016-present, Facebook, Inc. # All rights reserved. # -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. -# ########################################################################## +# 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). +# ################################################################ # Standard variables for installation DESTDIR ?= diff --git a/contrib/pzstd/Pzstd.h b/contrib/pzstd/Pzstd.h index 1e29a7170..79d1fcca2 100644 --- a/contrib/pzstd/Pzstd.h +++ b/contrib/pzstd/Pzstd.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #pragma once diff --git a/contrib/pzstd/test/PzstdTest.cpp b/contrib/pzstd/test/PzstdTest.cpp index cadfa83f7..5c7d66310 100644 --- a/contrib/pzstd/test/PzstdTest.cpp +++ b/contrib/pzstd/test/PzstdTest.cpp @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include "Pzstd.h" extern "C" { diff --git a/contrib/pzstd/test/RoundTripTest.cpp b/contrib/pzstd/test/RoundTripTest.cpp index ed2ea770c..36af0673a 100644 --- a/contrib/pzstd/test/RoundTripTest.cpp +++ b/contrib/pzstd/test/RoundTripTest.cpp @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ extern "C" { #include "datagen.h" diff --git a/contrib/pzstd/utils/Buffer.h b/contrib/pzstd/utils/Buffer.h index ab25bac9c..f69c3b4d9 100644 --- a/contrib/pzstd/utils/Buffer.h +++ b/contrib/pzstd/utils/Buffer.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #pragma once diff --git a/contrib/pzstd/utils/FileSystem.h b/contrib/pzstd/utils/FileSystem.h index 7d597047f..3cfbe86e5 100644 --- a/contrib/pzstd/utils/FileSystem.h +++ b/contrib/pzstd/utils/FileSystem.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #pragma once diff --git a/contrib/pzstd/utils/Range.h b/contrib/pzstd/utils/Range.h index 111e98f58..7e2559cc9 100644 --- a/contrib/pzstd/utils/Range.h +++ b/contrib/pzstd/utils/Range.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ /** diff --git a/contrib/pzstd/utils/ResourcePool.h b/contrib/pzstd/utils/ResourcePool.h index ed011306b..a6ff5ffc5 100644 --- a/contrib/pzstd/utils/ResourcePool.h +++ b/contrib/pzstd/utils/ResourcePool.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #pragma once diff --git a/contrib/pzstd/utils/WorkQueue.h b/contrib/pzstd/utils/WorkQueue.h index 780e5360f..1d14d922c 100644 --- a/contrib/pzstd/utils/WorkQueue.h +++ b/contrib/pzstd/utils/WorkQueue.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #pragma once diff --git a/contrib/pzstd/utils/test/WorkQueueTest.cpp b/contrib/pzstd/utils/test/WorkQueueTest.cpp index 8caf170d2..14cf77304 100644 --- a/contrib/pzstd/utils/test/WorkQueueTest.cpp +++ b/contrib/pzstd/utils/test/WorkQueueTest.cpp @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include "utils/Buffer.h" #include "utils/WorkQueue.h" diff --git a/doc/educational_decoder/harness.c b/doc/educational_decoder/harness.c index 982e066e2..47882b168 100644 --- a/doc/educational_decoder/harness.c +++ b/doc/educational_decoder/harness.c @@ -2,9 +2,9 @@ * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include diff --git a/doc/educational_decoder/zstd_decompress.h b/doc/educational_decoder/zstd_decompress.h index 41009909b..a01fde331 100644 --- a/doc/educational_decoder/zstd_decompress.h +++ b/doc/educational_decoder/zstd_decompress.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2017-present, Facebook, Inc. + * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ /******* EXPOSED TYPES ********************************************************/ diff --git a/lib/common/threading.h b/lib/common/threading.h index bd4b654c2..8194bc6fa 100644 --- a/lib/common/threading.h +++ b/lib/common/threading.h @@ -2,9 +2,9 @@ * Copyright (c) 2016 Tino Reichardt * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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 can contact the author at: * - zstdmt source repository: https://github.com/mcmilk/zstdmt diff --git a/tests/fuzz/Makefile b/tests/fuzz/Makefile index da22ed0d0..c6327068f 100644 --- a/tests/fuzz/Makefile +++ b/tests/fuzz/Makefile @@ -1,13 +1,11 @@ -# ########################################################################## +# ################################################################ # Copyright (c) 2016-present, Facebook, Inc. # All rights reserved. # -# This Makefile is validated for Linux, and macOS targets -# -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. -# ########################################################################## +# 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). +# ################################################################ CFLAGS ?= -O3 CXXFLAGS ?= -O3 diff --git a/tests/fuzz/fuzz.h b/tests/fuzz/fuzz.h index 5b71aba89..3017db3aa 100644 --- a/tests/fuzz/fuzz.h +++ b/tests/fuzz/fuzz.h @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ /** diff --git a/tests/fuzz/regression_driver.c b/tests/fuzz/regression_driver.c index eee5f0a2a..41fdcc940 100644 --- a/tests/fuzz/regression_driver.c +++ b/tests/fuzz/regression_driver.c @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include "fuzz.h" diff --git a/tests/fuzz/simple_round_trip.c b/tests/fuzz/simple_round_trip.c index 703ea5826..63472bb44 100644 --- a/tests/fuzz/simple_round_trip.c +++ b/tests/fuzz/simple_round_trip.c @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ /** diff --git a/tests/fuzz/stream_decompress.c b/tests/fuzz/stream_decompress.c index 778a426de..ae853dc8c 100644 --- a/tests/fuzz/stream_decompress.c +++ b/tests/fuzz/stream_decompress.c @@ -1,10 +1,10 @@ -/** - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +/* + * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ /** diff --git a/tests/fuzz/stream_round_trip.c b/tests/fuzz/stream_round_trip.c index 17c7dfdd2..74adbeaba 100644 --- a/tests/fuzz/stream_round_trip.c +++ b/tests/fuzz/stream_round_trip.c @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ /** From b0cb081dc81a4455f90624e0c849b8bad5f51820 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 31 Aug 2017 12:20:50 -0700 Subject: [PATCH 076/248] last batch of header files changed to reflect new license (#825) only remains to update contrib/linux-kernel (@terrelln) --- build/cmake/lib/CMakeLists.txt | 21 +++++++++------------ contrib/adaptive-compression/adapt.c | 8 ++++---- contrib/pzstd/Options.cpp | 8 ++++---- contrib/pzstd/Pzstd.cpp | 8 ++++---- contrib/pzstd/test/OptionsTest.cpp | 8 ++++---- contrib/seekable_format/zstdseek_compress.c | 8 ++++---- doc/educational_decoder/zstd_decompress.c | 8 ++++---- lib/Makefile | 14 ++++++-------- programs/Makefile | 10 ++++------ tests/Makefile | 14 ++++++-------- tests/test-zstd-speed.py | 10 +++++----- tests/test-zstd-versions.py | 10 +++++----- 12 files changed, 59 insertions(+), 68 deletions(-) diff --git a/build/cmake/lib/CMakeLists.txt b/build/cmake/lib/CMakeLists.txt index f763733bc..8371192c5 100644 --- a/build/cmake/lib/CMakeLists.txt +++ b/build/cmake/lib/CMakeLists.txt @@ -1,13 +1,10 @@ # ################################################################ -# * Copyright (c) 2014-present, Yann Collet, Facebook, Inc. -# * All rights reserved. -# * -# * This source code is licensed under the BSD-style license found in the -# * LICENSE file in the root directory of this source tree. An additional grant -# * of patent rights can be found in the PATENTS file in the same directory. +# Copyright (c) 2015-present, Yann Collet, Facebook, Inc. +# All rights reserved. # -# You can contact the author at : -# - zstd homepage : http://www.zstd.net/ +# 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). # ################################################################ PROJECT(libzstd) @@ -151,10 +148,10 @@ IF (UNIX) ENDIF (UNIX) # install target -INSTALL(FILES - ${LIBRARY_DIR}/zstd.h - ${LIBRARY_DIR}/deprecated/zbuff.h - ${LIBRARY_DIR}/dictBuilder/zdict.h +INSTALL(FILES + ${LIBRARY_DIR}/zstd.h + ${LIBRARY_DIR}/deprecated/zbuff.h + ${LIBRARY_DIR}/dictBuilder/zdict.h ${LIBRARY_DIR}/common/zstd_errors.h DESTINATION "include") diff --git a/contrib/adaptive-compression/adapt.c b/contrib/adaptive-compression/adapt.c index e449e2a5f..8f9c678c5 100644 --- a/contrib/adaptive-compression/adapt.c +++ b/contrib/adaptive-compression/adapt.c @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include /* fprintf */ diff --git a/contrib/pzstd/Options.cpp b/contrib/pzstd/Options.cpp index 1f53f2bff..d9b216b42 100644 --- a/contrib/pzstd/Options.cpp +++ b/contrib/pzstd/Options.cpp @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include "Options.h" #include "util.h" diff --git a/contrib/pzstd/Pzstd.cpp b/contrib/pzstd/Pzstd.cpp index ae5d73444..1eb4ce14c 100644 --- a/contrib/pzstd/Pzstd.cpp +++ b/contrib/pzstd/Pzstd.cpp @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include "Pzstd.h" #include "SkippableFrame.h" diff --git a/contrib/pzstd/test/OptionsTest.cpp b/contrib/pzstd/test/OptionsTest.cpp index b3efe2b7e..e60114825 100644 --- a/contrib/pzstd/test/OptionsTest.cpp +++ b/contrib/pzstd/test/OptionsTest.cpp @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include "Options.h" diff --git a/contrib/seekable_format/zstdseek_compress.c b/contrib/seekable_format/zstdseek_compress.c index 5fe26ed28..df2074988 100644 --- a/contrib/seekable_format/zstdseek_compress.c +++ b/contrib/seekable_format/zstdseek_compress.c @@ -1,10 +1,10 @@ -/** +/* * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ #include /* malloc, free */ diff --git a/doc/educational_decoder/zstd_decompress.c b/doc/educational_decoder/zstd_decompress.c index af10db528..bea0e0ce1 100644 --- a/doc/educational_decoder/zstd_decompress.c +++ b/doc/educational_decoder/zstd_decompress.c @@ -2,9 +2,9 @@ * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ /// Zstandard educational decoder implementation @@ -1289,7 +1289,7 @@ static void execute_sequences(frame_context_t *const ctx, ostream_t *const out, // Copy any leftover literals { size_t len = IO_istream_len(&litstream); - copy_literals(len, &litstream, out); + copy_literals(len, &litstream, out); total_output += len; } diff --git a/lib/Makefile b/lib/Makefile index e31ce0438..b12fd6135 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,13 +1,11 @@ -# ########################################################################## -# Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +# ################################################################ +# Copyright (c) 2015-present, Yann Collet, Facebook, Inc. # All rights reserved. # -# This Makefile is validated for Linux, macOS, *BSD, Hurd, Solaris, MSYS2 targets -# -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. -# ########################################################################## +# 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). +# ################################################################ # Version numbers LIBVER_MAJOR_SCRIPT:=`sed -n '/define ZSTD_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ./zstd.h` diff --git a/programs/Makefile b/programs/Makefile index 5fd3703d4..62b558eeb 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -1,12 +1,10 @@ -# ########################################################################## +# ################################################################ # Copyright (c) 2015-present, Yann Collet, Facebook, Inc. # All rights reserved. # -# This Makefile is validated for Linux, macOS, *BSD, Hurd, Solaris, MSYS2 targets -# -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. +# 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). # ########################################################################## # zstd : Command Line Utility, supporting gzip-like arguments # zstd32 : Same as zstd, but forced to compile in 32-bits mode diff --git a/tests/Makefile b/tests/Makefile index 3be79c159..4bffe9137 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,13 +1,11 @@ -# ########################################################################## -# Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +# ################################################################ +# Copyright (c) 2015-present, Yann Collet, Facebook, Inc. # All rights reserved. # -# This Makefile is validated for Linux, macOS, *BSD, Hurd, Solaris, MSYS2 targets -# -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. -# ########################################################################## +# 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). +# ################################################################ # datagen : Synthetic and parametrable data generator, for tests # fullbench : Precisely measure speed for each zstd inner functions # fullbench32: Same as fullbench, but forced to compile in 32-bits mode diff --git a/tests/test-zstd-speed.py b/tests/test-zstd-speed.py index 56108a5ca..1096d5e4e 100755 --- a/tests/test-zstd-speed.py +++ b/tests/test-zstd-speed.py @@ -1,13 +1,13 @@ #! /usr/bin/env python3 -# +# ################################################################ # Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. # All rights reserved. # -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. -# +# 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). +# ########################################################################## # Limitations: # - doesn't support filenames with spaces diff --git a/tests/test-zstd-versions.py b/tests/test-zstd-versions.py index a5a713009..f2deac1f2 100755 --- a/tests/test-zstd-versions.py +++ b/tests/test-zstd-versions.py @@ -1,14 +1,14 @@ #!/usr/bin/env python3 """Test zstd interoperability between versions""" -# +# ################################################################ # Copyright (c) 2016-present, Yann Collet, Facebook, Inc. # All rights reserved. # -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. -# +# 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). +# ################################################################ import filecmp import glob From f9252d8347d3faa8197fdcc1aa9f570c3e2c9b8e Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 31 Aug 2017 12:48:36 -0700 Subject: [PATCH 077/248] [linux-kernel] Update license --- .../0002-lib-Add-zstd-modules.patch | 70 +++++++------------ contrib/linux-kernel/include/linux/zstd.h | 2 - contrib/linux-kernel/lib/zstd/compress.c | 2 - contrib/linux-kernel/lib/zstd/decompress.c | 2 - contrib/linux-kernel/lib/zstd/error_private.h | 2 - contrib/linux-kernel/lib/zstd/mem.h | 2 - contrib/linux-kernel/lib/zstd/zstd_common.c | 2 - contrib/linux-kernel/lib/zstd/zstd_internal.h | 2 - contrib/linux-kernel/lib/zstd/zstd_opt.h | 2 - contrib/linux-kernel/test/DecompressCrash.c | 6 +- contrib/linux-kernel/test/RoundTripCrash.c | 6 +- contrib/linux-kernel/xxhash_test.c | 14 ++-- contrib/linux-kernel/zstd_compress_test.c | 12 +--- contrib/linux-kernel/zstd_decompress_test.c | 12 +--- 14 files changed, 43 insertions(+), 93 deletions(-) diff --git a/contrib/linux-kernel/0002-lib-Add-zstd-modules.patch b/contrib/linux-kernel/0002-lib-Add-zstd-modules.patch index eb8b8b288..c3bbaed73 100644 --- a/contrib/linux-kernel/0002-lib-Add-zstd-modules.patch +++ b/contrib/linux-kernel/0002-lib-Add-zstd-modules.patch @@ -1,4 +1,4 @@ -From b7f044163968d724be55bf4841fd80babe036dc2 Mon Sep 17 00:00:00 2001 +From 2b29ec569f8438a0307debd29873859ca6d407fc Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Mon, 17 Jul 2017 17:08:19 -0700 Subject: [PATCH v5 2/5] lib: Add zstd modules @@ -121,26 +121,26 @@ v4 -> v5: - Fix rare compression bug from upstream commit 308047eb5d - Fix bug introduced in v3 when working around the gcc-7 bug - include/linux/zstd.h | 1157 +++++++++++++++ + include/linux/zstd.h | 1155 +++++++++++++++ lib/Kconfig | 8 + lib/Makefile | 2 + lib/zstd/Makefile | 18 + lib/zstd/bitstream.h | 374 +++++ - lib/zstd/compress.c | 3484 +++++++++++++++++++++++++++++++++++++++++++++ - lib/zstd/decompress.c | 2528 ++++++++++++++++++++++++++++++++ + lib/zstd/compress.c | 3482 +++++++++++++++++++++++++++++++++++++++++++++ + lib/zstd/decompress.c | 2526 ++++++++++++++++++++++++++++++++ lib/zstd/entropy_common.c | 243 ++++ - lib/zstd/error_private.h | 53 + + lib/zstd/error_private.h | 51 + lib/zstd/fse.h | 575 ++++++++ lib/zstd/fse_compress.c | 795 +++++++++++ lib/zstd/fse_decompress.c | 332 +++++ lib/zstd/huf.h | 212 +++ lib/zstd/huf_compress.c | 770 ++++++++++ lib/zstd/huf_decompress.c | 960 +++++++++++++ - lib/zstd/mem.h | 151 ++ - lib/zstd/zstd_common.c | 75 + - lib/zstd/zstd_internal.h | 263 ++++ - lib/zstd/zstd_opt.h | 1014 +++++++++++++ - 19 files changed, 13014 insertions(+) + lib/zstd/mem.h | 149 ++ + lib/zstd/zstd_common.c | 73 + + lib/zstd/zstd_internal.h | 261 ++++ + lib/zstd/zstd_opt.h | 1012 +++++++++++++ + 19 files changed, 12998 insertions(+) create mode 100644 include/linux/zstd.h create mode 100644 lib/zstd/Makefile create mode 100644 lib/zstd/bitstream.h @@ -161,18 +161,16 @@ v4 -> v5: diff --git a/include/linux/zstd.h b/include/linux/zstd.h new file mode 100644 -index 0000000..249575e +index 0000000..305efd0 --- /dev/null +++ b/include/linux/zstd.h -@@ -0,0 +1,1157 @@ +@@ -0,0 +1,1155 @@ +/* + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of https://github.com/facebook/zstd. -+ * An additional grant of patent rights can be found in the PATENTS file in the -+ * same directory. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the @@ -1760,18 +1758,16 @@ index 0000000..a826b99 +#endif /* BITSTREAM_H_MODULE */ diff --git a/lib/zstd/compress.c b/lib/zstd/compress.c new file mode 100644 -index 0000000..f9166cf +index 0000000..ff18ae6 --- /dev/null +++ b/lib/zstd/compress.c -@@ -0,0 +1,3484 @@ +@@ -0,0 +1,3482 @@ +/** + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of https://github.com/facebook/zstd. -+ * An additional grant of patent rights can be found in the PATENTS file in the -+ * same directory. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the @@ -5250,18 +5246,16 @@ index 0000000..f9166cf +MODULE_DESCRIPTION("Zstd Compressor"); diff --git a/lib/zstd/decompress.c b/lib/zstd/decompress.c new file mode 100644 -index 0000000..b178467 +index 0000000..72df4828 --- /dev/null +++ b/lib/zstd/decompress.c -@@ -0,0 +1,2528 @@ +@@ -0,0 +1,2526 @@ +/** + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of https://github.com/facebook/zstd. -+ * An additional grant of patent rights can be found in the PATENTS file in the -+ * same directory. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the @@ -8033,18 +8027,16 @@ index 0000000..2b0a643 +} diff --git a/lib/zstd/error_private.h b/lib/zstd/error_private.h new file mode 100644 -index 0000000..1a60b31 +index 0000000..2062ff0 --- /dev/null +++ b/lib/zstd/error_private.h -@@ -0,0 +1,53 @@ +@@ -0,0 +1,51 @@ +/** + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of https://github.com/facebook/zstd. -+ * An additional grant of patent rights can be found in the PATENTS file in the -+ * same directory. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the @@ -11772,18 +11764,16 @@ index 0000000..6526482 +} diff --git a/lib/zstd/mem.h b/lib/zstd/mem.h new file mode 100644 -index 0000000..3a0f34c +index 0000000..42a697b --- /dev/null +++ b/lib/zstd/mem.h -@@ -0,0 +1,151 @@ +@@ -0,0 +1,149 @@ +/** + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of https://github.com/facebook/zstd. -+ * An additional grant of patent rights can be found in the PATENTS file in the -+ * same directory. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the @@ -11929,18 +11919,16 @@ index 0000000..3a0f34c +#endif /* MEM_H_MODULE */ diff --git a/lib/zstd/zstd_common.c b/lib/zstd/zstd_common.c new file mode 100644 -index 0000000..a282624 +index 0000000..e5f06d7 --- /dev/null +++ b/lib/zstd/zstd_common.c -@@ -0,0 +1,75 @@ +@@ -0,0 +1,73 @@ +/** + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of https://github.com/facebook/zstd. -+ * An additional grant of patent rights can be found in the PATENTS file in the -+ * same directory. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the @@ -12010,18 +11998,16 @@ index 0000000..a282624 +} diff --git a/lib/zstd/zstd_internal.h b/lib/zstd/zstd_internal.h new file mode 100644 -index 0000000..1a79fab +index 0000000..a0fb83e --- /dev/null +++ b/lib/zstd/zstd_internal.h -@@ -0,0 +1,263 @@ +@@ -0,0 +1,261 @@ +/** + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of https://github.com/facebook/zstd. -+ * An additional grant of patent rights can be found in the PATENTS file in the -+ * same directory. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the @@ -12279,18 +12265,16 @@ index 0000000..1a79fab +#endif /* ZSTD_CCOMMON_H_MODULE */ diff --git a/lib/zstd/zstd_opt.h b/lib/zstd/zstd_opt.h new file mode 100644 -index 0000000..55e1b4c +index 0000000..ecdd725 --- /dev/null +++ b/lib/zstd/zstd_opt.h -@@ -0,0 +1,1014 @@ +@@ -0,0 +1,1012 @@ +/** + * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of https://github.com/facebook/zstd. -+ * An additional grant of patent rights can be found in the PATENTS file in the -+ * same directory. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the @@ -13298,4 +13282,4 @@ index 0000000..55e1b4c + +#endif /* ZSTD_OPT_H_91842398743 */ -- -2.9.3 +2.9.5 diff --git a/contrib/linux-kernel/include/linux/zstd.h b/contrib/linux-kernel/include/linux/zstd.h index 249575e24..305efd093 100644 --- a/contrib/linux-kernel/include/linux/zstd.h +++ b/contrib/linux-kernel/include/linux/zstd.h @@ -4,8 +4,6 @@ * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of https://github.com/facebook/zstd. - * An additional grant of patent rights can be found in the PATENTS file in the - * same directory. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the diff --git a/contrib/linux-kernel/lib/zstd/compress.c b/contrib/linux-kernel/lib/zstd/compress.c index f9166cf4f..ff18ae6d6 100644 --- a/contrib/linux-kernel/lib/zstd/compress.c +++ b/contrib/linux-kernel/lib/zstd/compress.c @@ -4,8 +4,6 @@ * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of https://github.com/facebook/zstd. - * An additional grant of patent rights can be found in the PATENTS file in the - * same directory. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the diff --git a/contrib/linux-kernel/lib/zstd/decompress.c b/contrib/linux-kernel/lib/zstd/decompress.c index b17846725..72df4828d 100644 --- a/contrib/linux-kernel/lib/zstd/decompress.c +++ b/contrib/linux-kernel/lib/zstd/decompress.c @@ -4,8 +4,6 @@ * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of https://github.com/facebook/zstd. - * An additional grant of patent rights can be found in the PATENTS file in the - * same directory. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the diff --git a/contrib/linux-kernel/lib/zstd/error_private.h b/contrib/linux-kernel/lib/zstd/error_private.h index 1a60b31f7..2062ff05a 100644 --- a/contrib/linux-kernel/lib/zstd/error_private.h +++ b/contrib/linux-kernel/lib/zstd/error_private.h @@ -4,8 +4,6 @@ * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of https://github.com/facebook/zstd. - * An additional grant of patent rights can be found in the PATENTS file in the - * same directory. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the diff --git a/contrib/linux-kernel/lib/zstd/mem.h b/contrib/linux-kernel/lib/zstd/mem.h index 3a0f34c87..42a697b74 100644 --- a/contrib/linux-kernel/lib/zstd/mem.h +++ b/contrib/linux-kernel/lib/zstd/mem.h @@ -4,8 +4,6 @@ * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of https://github.com/facebook/zstd. - * An additional grant of patent rights can be found in the PATENTS file in the - * same directory. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the diff --git a/contrib/linux-kernel/lib/zstd/zstd_common.c b/contrib/linux-kernel/lib/zstd/zstd_common.c index a282624ee..e5f06d771 100644 --- a/contrib/linux-kernel/lib/zstd/zstd_common.c +++ b/contrib/linux-kernel/lib/zstd/zstd_common.c @@ -4,8 +4,6 @@ * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of https://github.com/facebook/zstd. - * An additional grant of patent rights can be found in the PATENTS file in the - * same directory. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the diff --git a/contrib/linux-kernel/lib/zstd/zstd_internal.h b/contrib/linux-kernel/lib/zstd/zstd_internal.h index 1a79fab9e..a0fb83e34 100644 --- a/contrib/linux-kernel/lib/zstd/zstd_internal.h +++ b/contrib/linux-kernel/lib/zstd/zstd_internal.h @@ -4,8 +4,6 @@ * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of https://github.com/facebook/zstd. - * An additional grant of patent rights can be found in the PATENTS file in the - * same directory. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the diff --git a/contrib/linux-kernel/lib/zstd/zstd_opt.h b/contrib/linux-kernel/lib/zstd/zstd_opt.h index 55e1b4cba..ecdd7259e 100644 --- a/contrib/linux-kernel/lib/zstd/zstd_opt.h +++ b/contrib/linux-kernel/lib/zstd/zstd_opt.h @@ -4,8 +4,6 @@ * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of https://github.com/facebook/zstd. - * An additional grant of patent rights can be found in the PATENTS file in the - * same directory. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the diff --git a/contrib/linux-kernel/test/DecompressCrash.c b/contrib/linux-kernel/test/DecompressCrash.c index b5b673aad..2ab7dfe52 100644 --- a/contrib/linux-kernel/test/DecompressCrash.c +++ b/contrib/linux-kernel/test/DecompressCrash.c @@ -2,9 +2,9 @@ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ /* diff --git a/contrib/linux-kernel/test/RoundTripCrash.c b/contrib/linux-kernel/test/RoundTripCrash.c index 44c67f3ab..4f968023d 100644 --- a/contrib/linux-kernel/test/RoundTripCrash.c +++ b/contrib/linux-kernel/test/RoundTripCrash.c @@ -2,9 +2,9 @@ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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). */ /* diff --git a/contrib/linux-kernel/xxhash_test.c b/contrib/linux-kernel/xxhash_test.c index 5c1101b6f..eb0fb1cd7 100644 --- a/contrib/linux-kernel/xxhash_test.c +++ b/contrib/linux-kernel/xxhash_test.c @@ -2,19 +2,13 @@ * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. This program is dual-licensed; you may select - * either version 2 of the GNU General Public License ("GPL") or BSD license - * ("BSD"). + * 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). */ /* DO_XXH should be 32 or 64 for xxh32 and xxh64 respectively */ -#define DO_XXH 0 +#define DO_XXH 0 /* DO_CRC should be 0 or 1 */ #define DO_CRC 0 /* Buffer size */ diff --git a/contrib/linux-kernel/zstd_compress_test.c b/contrib/linux-kernel/zstd_compress_test.c index bf856b796..dc17adf81 100644 --- a/contrib/linux-kernel/zstd_compress_test.c +++ b/contrib/linux-kernel/zstd_compress_test.c @@ -2,15 +2,9 @@ * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. This program is dual-licensed; you may select - * either version 2 of the GNU General Public License ("GPL") or BSD license - * ("BSD"). + * 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). */ /* Compression level or 0 to disable */ diff --git a/contrib/linux-kernel/zstd_decompress_test.c b/contrib/linux-kernel/zstd_decompress_test.c index 4905a5ac5..f6efddd30 100644 --- a/contrib/linux-kernel/zstd_decompress_test.c +++ b/contrib/linux-kernel/zstd_decompress_test.c @@ -2,15 +2,9 @@ * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. This program is dual-licensed; you may select - * either version 2 of the GNU General Public License ("GPL") or BSD license - * ("BSD"). + * 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). */ /* Compression level or 0 to disable */ From 6a546efb8c90adf7865801e313da433ce8406ce1 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Fri, 28 Jul 2017 15:51:33 -0700 Subject: [PATCH 078/248] Add long distance matcher Move last literals section to ZSTD_block_internal --- lib/common/zstd_internal.h | 14 + lib/compress/zstd_compress.c | 934 +++++++++++++++++++++++++++++++---- lib/compress/zstd_opt.h | 24 +- lib/zstd.h | 4 +- programs/bench.c | 6 +- programs/bench.h | 1 + programs/fileio.c | 6 + programs/fileio.h | 1 + programs/zstdcli.c | 7 +- tests/fuzzer.c | 4 +- tests/playTests.sh | 22 + tests/zstreamtest.c | 2 + 12 files changed, 901 insertions(+), 124 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 19c0a6261..49b21c2db 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -274,6 +274,20 @@ typedef struct { const BYTE* cachedLiterals; } optState_t; +typedef struct { + U32 offset; + U32 checksum; +} ldmEntry_t; + +typedef struct { + ldmEntry_t* hashTable; + BYTE* bucketOffsets; + U32 ldmEnable; /* 1 if enable long distance matching */ + U32 hashLog; /* log size of hashTable */ + U32 bucketLog; /* log number of buckets, at most 4 */ + U32 hashEveryLog; +} ldmState_t; + typedef struct { U32 hufCTable[HUF_CTABLE_SIZE_U32(255)]; FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)]; diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 5adeb480b..331b21207 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -36,6 +36,13 @@ static const U32 g_searchStrength = 8; /* control skip over incompressible dat #define HASH_READ_SIZE 8 typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e; +#define LDM_BUCKET_SIZE_LOG 3 +#define LDM_BUCKET_SIZE_LOG_MAX 4 +#define LDM_MIN_MATCH_LENGTH 64 +#define LDM_WINDOW_LOG 27 +#define LDM_HASH_LOG 20 +#define LDM_HASH_CHAR_OFFSET 10 + /*-************************************* * Helper functions @@ -46,7 +53,6 @@ size_t ZSTD_compressBound(size_t srcSize) { return srcSize + (srcSize >> 8) + margin; } - /*-************************************* * Sequence storage ***************************************/ @@ -101,6 +107,7 @@ struct ZSTD_CCtx_s { seqStore_t seqStore; /* sequences storage ptrs */ optState_t optState; + ldmState_t ldmState; /* long distance matching state */ U32* hashTable; U32* hashTable3; U32* chainTable; @@ -354,6 +361,16 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v DEBUGLOG(5, " setting overlap with nbThreads == %u", cctx->requestedParams.nbThreads); return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); + case ZSTD_p_longDistanceMatching: + /* TODO */ + if (cctx->cdict) return ERROR(stage_wrong); + cctx->ldmState.ldmEnable = value>0; + if (value != 0) { + ZSTD_cLevelToCParams(cctx); + cctx->requestedParams.cParams.windowLog = LDM_WINDOW_LOG; + } + return 0; + default: return ERROR(parameter_unsupported); } } @@ -453,6 +470,10 @@ size_t ZSTD_CCtxParam_setParameter( if (params->nbThreads <= 1) return ERROR(parameter_unsupported); return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_overlapSectionLog, value); + case ZSTD_p_longDistanceMatching : + /* TODO */ + return ERROR(parameter_unsupported); + default: return ERROR(parameter_unsupported); } } @@ -677,7 +698,11 @@ size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* pa ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<appliedParams)) { + /* TODO: For now, reset if long distance matching is enabled */ + if (ZSTD_equivalentParams(params, zc->appliedParams) && + !zc->ldmState.ldmEnable) { DEBUGLOG(5, "ZSTD_equivalentParams()==1"); zc->entropy->hufCTable_repeatMode = HUF_repeat_none; zc->entropy->offcode_repeatMode = FSE_repeat_none; @@ -787,6 +814,15 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, return ZSTD_continueCCtx(zc, params, pledgedSrcSize); } } + { + zc->ldmState.hashLog = LDM_HASH_LOG; + zc->ldmState.bucketLog = + MIN(LDM_BUCKET_SIZE_LOG, LDM_BUCKET_SIZE_LOG_MAX); + zc->ldmState.hashEveryLog = + params.cParams.windowLog < zc->ldmState.hashLog ? + 0 : params.cParams.windowLog - zc->ldmState.hashLog; + } + { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog); U32 const divider = (params.cParams.searchLength==3) ? 3 : 4; size_t const maxNbSeq = blockSize / divider; @@ -802,6 +838,14 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, size_t const buffInSize = (zbuff==ZSTDb_buffered) ? ((size_t)1 << params.cParams.windowLog) + blockSize : 0; void* ptr; + size_t const ldmHSize = ((size_t)1) << zc->ldmState.hashLog; + size_t const ldmBucketSize = + ((size_t)1) << (zc->ldmState.hashLog - zc->ldmState.bucketLog); + size_t const ldmPotentialSpace = + ldmBucketSize + (ldmHSize * (sizeof(ldmEntry_t))); + size_t const ldmSpace = zc->ldmState.ldmEnable ? + ldmPotentialSpace : 0; + /* Check if workSpace is large enough, alloc a new one if needed */ { size_t const entropySpace = sizeof(ZSTD_entropyCTables_t); size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<workSpaceSize < neededSpace) { /* too small : resize /*/ + if (zc->workSpaceSize < neededSpace) { /* too small : resize */ DEBUGLOG(5, "Need to update workSpaceSize from %uK to %uK \n", (unsigned)zc->workSpaceSize>>10, (unsigned)neededSpace>>10); @@ -878,6 +922,16 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, ptr = zc->optState.priceTable + ZSTD_OPT_NUM+1; } + /* ldm space */ + if (zc->ldmState.ldmEnable) { + if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, ldmSpace); + assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ + zc->ldmState.hashTable = (ldmEntry_t*)ptr; + ptr = zc->ldmState.hashTable + ldmHSize; + zc->ldmState.bucketOffsets = (BYTE*)ptr; + ptr = zc->ldmState.bucketOffsets + ldmBucketSize; + } + /* table Space */ if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */ assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ @@ -990,6 +1044,18 @@ static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reduce } } +/*! ZSTD_ldm_reduceTable() : + * reduce table indexes by `reducerValue` */ +static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size, + U32 const reducerValue) +{ + U32 u; + for (u = 0; u < size; u++) { + if (table[u].offset < reducerValue) table[u].offset = 0; + else table[u].offset -= reducerValue; + } +} + /*! ZSTD_reduceIndex() : * rescale all indexes to avoid future overflow (indexes are U32) */ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue) @@ -1002,6 +1068,12 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue) { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0; ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); } + + { if (zc->ldmState.ldmEnable) { + U32 const ldmHSize = 1 << LDM_HASH_LOG; + ZSTD_ldm_reduceTable(zc->ldmState.hashTable, ldmHSize, reducerValue); + } + } } @@ -1611,7 +1683,6 @@ static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) } } - /*-************************************* * Fast Scan ***************************************/ @@ -1630,11 +1701,10 @@ static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls) } } - FORCE_INLINE -void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx, - const void* src, size_t srcSize, - const U32 mls) +size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx, + const void* src, size_t srcSize, + const U32 mls) { U32* const hashTable = cctx->hashTable; U32 const hBits = cctx->appliedParams.cParams.hashLog; @@ -1681,7 +1751,6 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx, while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); } @@ -1711,15 +1780,11 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx, seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved; seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved; - /* Last Literals */ - { size_t const lastLLSize = iend - anchor; - memcpy(seqStorePtr->lit, anchor, lastLLSize); - seqStorePtr->lit += lastLLSize; - } + /* Return the last literals size */ + return iend - anchor; } - -static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx, +static size_t ZSTD_compressBlock_fast(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { const U32 mls = ctx->appliedParams.cParams.searchLength; @@ -1727,18 +1792,19 @@ static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx, { default: /* includes case 3 */ case 4 : - ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return; + return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); case 5 : - ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return; + return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); case 6 : - ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return; + return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); case 7 : - ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return; + return ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); } } -static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, +static size_t ZSTD_compressBlock_fast_extDict_generic( + ZSTD_CCtx* ctx, const void* src, size_t srcSize, const U32 mls) { @@ -1825,15 +1891,11 @@ static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, /* save reps for next block */ seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2; - /* Last Literals */ - { size_t const lastLLSize = iend - anchor; - memcpy(seqStorePtr->lit, anchor, lastLLSize); - seqStorePtr->lit += lastLLSize; - } + /* Return the last literals size */ + return iend - anchor; } - -static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, +static size_t ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { U32 const mls = ctx->appliedParams.cParams.searchLength; @@ -1841,13 +1903,13 @@ static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, { default: /* includes case 3 */ case 4 : - ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return; + return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); case 5 : - ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return; + return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); case 6 : - ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return; + return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); case 7 : - ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return; + return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); } } @@ -1875,7 +1937,7 @@ static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U3 FORCE_INLINE -void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx, +size_t ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx, const void* src, size_t srcSize, const U32 mls) { @@ -1921,6 +1983,7 @@ void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx, ip++; ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH); } else { + U32 offset; if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) { mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8; @@ -1982,33 +2045,32 @@ void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx, seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved; seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved; - /* Last Literals */ - { size_t const lastLLSize = iend - anchor; - memcpy(seqStorePtr->lit, anchor, lastLLSize); - seqStorePtr->lit += lastLLSize; - } + /* Return the last literals size */ + return iend - anchor; } -static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +static size_t ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, + const void* src, size_t srcSize) { const U32 mls = ctx->appliedParams.cParams.searchLength; switch(mls) { default: /* includes case 3 */ case 4 : - ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return; + return ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); case 5 : - ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return; + return ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); case 6 : - ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return; + return ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); case 7 : - ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return; + return ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); } } -static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx, +static size_t ZSTD_compressBlock_doubleFast_extDict_generic( + ZSTD_CCtx* ctx, const void* src, size_t srcSize, const U32 mls) { @@ -2131,15 +2193,12 @@ static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx, /* save reps for next block */ seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2; - /* Last Literals */ - { size_t const lastLLSize = iend - anchor; - memcpy(seqStorePtr->lit, anchor, lastLLSize); - seqStorePtr->lit += lastLLSize; - } + /* Return the last literals size */ + return iend - anchor; } -static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx, +static size_t ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { U32 const mls = ctx->appliedParams.cParams.searchLength; @@ -2147,13 +2206,13 @@ static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx, { default: /* includes case 3 */ case 4 : - ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return; + return ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); case 5 : - ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return; + return ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); case 6 : - ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return; + return ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); case 7 : - ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return; + return ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); } } @@ -2546,9 +2605,9 @@ FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS ( * Common parser - lazy strategy *********************************/ FORCE_INLINE -void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, - const void* src, size_t srcSize, - const U32 searchMethod, const U32 depth) +size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, + const void* src, size_t srcSize, + const U32 searchMethod, const U32 depth) { seqStore_t* seqStorePtr = &(ctx->seqStore); const BYTE* const istart = (const BYTE*)src; @@ -2678,37 +2737,38 @@ _storeSequence: seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : savedOffset; seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : savedOffset; - /* Last Literals */ - { size_t const lastLLSize = iend - anchor; - memcpy(seqStorePtr->lit, anchor, lastLLSize); - seqStorePtr->lit += lastLLSize; - } + /* Return the last literals size */ + return iend - anchor; } -static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +static size_t ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, + size_t srcSize) { - ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2); + return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2); } -static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +static size_t ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, + size_t srcSize) { - ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2); + return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2); } -static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +static size_t ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, + size_t srcSize) { - ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1); + return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1); } -static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +static size_t ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, + size_t srcSize) { - ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0); + return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0); } FORCE_INLINE -void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, +size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, const void* src, size_t srcSize, const U32 searchMethod, const U32 depth) { @@ -2774,7 +2834,7 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, /* let's try to find a better solution */ if (depth>=1) while (iprepToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2; - /* Last Literals */ - { size_t const lastLLSize = iend - anchor; - memcpy(seqStorePtr->lit, anchor, lastLLSize); - seqStorePtr->lit += lastLLSize; - } + /* Return the last literals size */ + return iend - anchor; } -void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +size_t ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0); + return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0); } -static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +static size_t ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1); + return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1); } -static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +static size_t ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2); + return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2); } -static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +static size_t ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2); + return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2); } /* The optimal parser */ #include "zstd_opt.h" -static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +static size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { #ifdef ZSTD_OPT_H_91842398743 - ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0); + return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0); #else (void)ctx; (void)src; (void)srcSize; - return; + return 0; #endif } -static void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +static size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { #ifdef ZSTD_OPT_H_91842398743 - ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1); + return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1); #else (void)ctx; (void)src; (void)srcSize; - return; + return 0; #endif } -static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +static size_t ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { #ifdef ZSTD_OPT_H_91842398743 - ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0); + return ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0); #else (void)ctx; (void)src; (void)srcSize; - return; + return 0; #endif } -static void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +static size_t ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { #ifdef ZSTD_OPT_H_91842398743 - ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1); + return ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1); #else (void)ctx; (void)src; (void)srcSize; - return; + return 0; #endif } - /* ZSTD_selectBlockCompressor() : * assumption : strat is a valid strategy */ -typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize); +typedef size_t (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize); static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict) { static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = { @@ -2967,18 +3023,687 @@ static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int return blockCompressor[extDict!=0][(U32)strat]; } +/*-************************************* +* Long distance matching +***************************************/ + +/** ZSTD_ldm_getSmallHash() : + * numBits should be <= 32 + * @return : the most significant numBits of value */ +static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits) +{ + assert(numBits <= 32); + return (U32)(value >> (64 - numBits)); +} + +/** ZSTD_ldm_getChecksum() : + * numBitsToDiscard should be <= 32 + * @return : the next most significant 32 bits after numBitsToDiscard */ +static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard) +{ + assert(numBitsToDiscard <= 32); + return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF; +} + +/** ZSTD_ldm_getTag() ; + * Given the hash, returns the most significant numTagBits bits + * after (32 + hbits) bits. + * + * If there are not enough bits remaining, return the last + * numTagBits bits. */ +static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits) +{ + if (32 - hbits < numTagBits) { + return hash & ((1 << numTagBits) - 1); + } else { + return (hash >> (32 - hbits - numTagBits)) & ((1 << numTagBits) - 1); + } +} + +/** ZSTD_ldm_getBucket() : + * Returns a pointer to the start of the bucket associated with hash. */ +static ldmEntry_t* ZSTD_ldm_getBucket(ldmState_t* ldmState, size_t hash) +{ + return ldmState->hashTable + (hash << ldmState->bucketLog); +} + +/** ZSTD_ldm_insertEntry() : + * Insert the entry with corresponding hash into the hash table */ +static void ZSTD_ldm_insertEntry(ldmState_t* ldmState, + size_t const hash, const ldmEntry_t entry) +{ + BYTE* const bucketOffsets = ldmState->bucketOffsets; + *(ZSTD_ldm_getBucket(ldmState, hash) + bucketOffsets[hash]) = entry; + bucketOffsets[hash]++; + bucketOffsets[hash] &= (1 << ldmState->bucketLog) - 1; +} + +/** ZSTD_ldm_makeEntryAndInsertByTag() : + * + * Gets the small hash, checksum, and tag from the rollingHash. + * + * If the tag matches (1 << ldmState->hashEveryLog)-1, then + * creates an ldmEntry from the offset, and inserts it into the hash table. + * + * hBits is the length of the small hash, which is the most significant hBits + * of rollingHash. The checksum is the next 32 most significant bits, followed + * by ldmState->hashEveryLog bits that make up the tag. */ +static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState, + U64 rollingHash, U32 hBits, + U32 const offset) +{ + U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmState->hashEveryLog); + U32 const tagMask = (1 << ldmState->hashEveryLog) - 1; + if (tag == tagMask) { + U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits); + U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); + ldmEntry_t entry; + entry.offset = offset; + entry.checksum = checksum; + ZSTD_ldm_insertEntry(ldmState, hash, entry); + } +} + +/** ZSTD_ldm_getRollingHash() : + * Get a 64-bit hash using the first len bytes from buf. + * + * Giving bytes s = s_1, s_2, ... s_k, the hash is defined to be + * H(s) = s_1*(a^(k-1)) + s_2*(a^(k-2)) + ... + s_k*(a^0) + * + * where the constant a is defined to be prime8bytes. + * + * The implementation adds an offset to each byte, so + * H(s) = (s_1 + HASH_CHAR_OFFSET)*(a^(k-1)) + ... */ +static U64 ZSTD_ldm_getRollingHash(const BYTE* buf, U32 len) +{ + U64 ret = 0; + U32 i; + for (i = 0; i < len; i++) { + ret *= prime8bytes; + ret += buf[i] + LDM_HASH_CHAR_OFFSET; + } + return ret; +} + +/** ZSTD_ldm_ipow() : + * Return base^exp. */ +static U64 ZSTD_ldm_ipow(U64 base, U64 exp) +{ + U64 ret = 1; + while (exp) { + if (exp & 1) { ret *= base; } + exp >>= 1; + base *= base; + } + return ret; +} + +/** ZSTD_ldm_updateHash() : + * Updates hash by removing toRemove and adding toAdd. + * + * Note: this currently relies on compiler optimization to avoid + * recalculating hashPower. */ +static U64 ZSTD_ldm_updateHash(U64 hash, BYTE toRemove, BYTE toAdd) +{ + U64 const hashPower = ZSTD_ldm_ipow(prime8bytes, LDM_MIN_MATCH_LENGTH - 1); + hash -= ((toRemove + LDM_HASH_CHAR_OFFSET) * hashPower); + hash *= prime8bytes; + hash += toAdd + LDM_HASH_CHAR_OFFSET; + return hash; +} + +/** ZSTD_ldm_countBackwardsMatch() : + * Returns the number of bytes that match backwards before pIn and pMatch. + * + * We count only bytes where pMatch >= pBase and pIn >= pAnchor. */ +static size_t ZSTD_ldm_countBackwardsMatch( + const BYTE* pIn, const BYTE* pAnchor, + const BYTE* pMatch, const BYTE* pBase) +{ + size_t matchLength = 0; + while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) { + pIn--; + pMatch--; + matchLength++; + } + return matchLength; +} + +/** ZSTD_ldm_fillFastTables() : + * + * Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies. + * This is similar to ZSTD_loadDictionaryContent. + * + * The tables for the other strategies are filled within their + * block compressors. */ +static size_t ZSTD_ldm_fillFastTables(ZSTD_CCtx* zc, const void* end) +{ + const BYTE* const iend = (const BYTE*)end; + const U32 mls = zc->appliedParams.cParams.searchLength; + + switch(zc->appliedParams.cParams.strategy) + { + case ZSTD_fast: + ZSTD_fillHashTable(zc, iend, mls); + zc->nextToUpdate = (U32)(iend - zc->base); + break; + + case ZSTD_dfast: + ZSTD_fillDoubleHashTable(zc, iend, mls); + zc->nextToUpdate = (U32)(iend - zc->base); + break; + + case ZSTD_greedy: + case ZSTD_lazy: + case ZSTD_lazy2: + case ZSTD_btlazy2: + case ZSTD_btopt: + case ZSTD_btultra: + break; + default: + assert(0); /* not possible : not a valid strategy id */ + } + + return 0; +} + +/** ZSTD_ldm_fillLdmHashTable() : + * + * Fills hashTable from (lastHashed + 1) to iend (non-inclusive). + * lastHash is the rolling hash that corresponds to lastHashed. + * + * Returns the rolling hash corresponding to position iend-1. */ +static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state, + U64 lastHash, const BYTE* lastHashed, + const BYTE* iend, const BYTE* base, + U32 hBits) +{ + U64 rollingHash = lastHash; + const BYTE* cur = lastHashed + 1; + + while (cur < iend) { + rollingHash = ZSTD_ldm_updateHash(rollingHash, cur[-1], + cur[LDM_MIN_MATCH_LENGTH-1]); + ZSTD_ldm_makeEntryAndInsertByTag(state, + rollingHash, hBits, + (U32)(cur - base)); + ++cur; + } + return rollingHash; +} + + +/** ZSTD_ldm_limitTableUpdate() : + * + * Sets cctx->nextToUpdate to a position corresponding closer to anchor + * if it is far way + * (after a long match, only update tables a limited amount). */ +static void ZSTD_ldm_limitTableUpdate(ZSTD_CCtx* cctx, const BYTE* anchor) +{ + U32 const current = (U32)(anchor - cctx->base); + if (current > cctx->nextToUpdate + 1024) { + cctx->nextToUpdate = + current - MIN(512, current - cctx->nextToUpdate - 1024); + } +} + +/** ZSTD_compressBlock_ldm_generic() : + * + * This is a block compressor intended for long distance matching. + * + * The function searches for matches of length at least LDM_MIN_MATCH_LENGTH + * using a hash table in cctx->ldmState. Matches can be at a distance of + * up to LDM_WINDOW_LOG. + * + * Upon finding a match, the unmatched literals are compressed using a + * ZSTD_blockCompressor (depending on the strategy in the compression + * parameters), which stores the matched sequences. The "long distance" + * match is then stored with the remaining literals from the + * ZSTD_blockCompressor. */ +FORCE_INLINE +size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx, + const void* src, size_t srcSize) +{ + ldmState_t* const ldmState = &(cctx->ldmState); + const U32 hBits = ldmState->hashLog - ldmState->bucketLog; + const U32 ldmBucketSize = (1 << ldmState->bucketLog); + const U32 ldmTagMask = (1 << ldmState->hashEveryLog) - 1; + seqStore_t* const seqStorePtr = &(cctx->seqStore); + const BYTE* const base = cctx->base; + const BYTE* const istart = (const BYTE*)src; + const BYTE* ip = istart; + const BYTE* anchor = istart; + const U32 lowestIndex = cctx->dictLimit; + const BYTE* const lowest = base + lowestIndex; + const BYTE* const iend = istart + srcSize; + const BYTE* const ilimit = iend - LDM_MIN_MATCH_LENGTH; + + const ZSTD_blockCompressor blockCompressor = + ZSTD_selectBlockCompressor(cctx->appliedParams.cParams.strategy, 0); + U32* const repToConfirm = seqStorePtr->repToConfirm; + U32 savedRep[ZSTD_REP_NUM]; + U64 rollingHash = 0; + const BYTE* lastHashed = NULL; + size_t i, lastLiterals; + + /* Save seqStorePtr->rep and copy repToConfirm */ + for (i = 0; i < ZSTD_REP_NUM; i++) + savedRep[i] = repToConfirm[i] = seqStorePtr->rep[i]; + + /* Main Search Loop */ + while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ + size_t mLength; + U32 const current = (U32)(ip - base); + size_t forwardMatchLength = 0, backwardMatchLength = 0; + ldmEntry_t* bestEntry = NULL; + if (ip != istart) { + rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0], + lastHashed[LDM_MIN_MATCH_LENGTH]); + } else { + rollingHash = ZSTD_ldm_getRollingHash(ip, LDM_MIN_MATCH_LENGTH); + } + lastHashed = ip; + + /* Do not insert and do not look for a match */ + if (ZSTD_ldm_getTag(rollingHash, hBits, ldmState->hashEveryLog) != + ldmTagMask) { + ip++; + continue; + } + + /* Get the best entry and compute the match lengths */ + { + ldmEntry_t* const bucket = + ZSTD_ldm_getBucket(ldmState, + ZSTD_ldm_getSmallHash(rollingHash, hBits)); + ldmEntry_t* cur; + size_t bestMatchLength = 0; + U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); + + for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) { + const BYTE* const pMatch = cur->offset + base; + size_t curForwardMatchLength, curBackwardMatchLength, + curTotalMatchLength; + if (cur->checksum != checksum || cur->offset <= lowestIndex) { + continue; + } + + curForwardMatchLength = ZSTD_count(ip, pMatch, iend); + if (curForwardMatchLength < LDM_MIN_MATCH_LENGTH) { + continue; + } + curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch( + ip, anchor, pMatch, lowest); + curTotalMatchLength = curForwardMatchLength + + curBackwardMatchLength; + + if (curTotalMatchLength > bestMatchLength) { + bestMatchLength = curTotalMatchLength; + forwardMatchLength = curForwardMatchLength; + backwardMatchLength = curBackwardMatchLength; + bestEntry = cur; + } + } + } + + /* No match found -- continue searching */ + if (bestEntry == NULL) { + ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, + hBits, current); + ip++; + continue; + } + + /* Match found */ + mLength = forwardMatchLength + backwardMatchLength; + ip -= backwardMatchLength; + + /* Call the block compressor on the remaining literals */ + { + U32 const matchIndex = bestEntry->offset; + const BYTE* const match = base + matchIndex - backwardMatchLength; + U32 const offset = (U32)(ip - match); + + /* Overwrite rep codes */ + for (i = 0; i < ZSTD_REP_NUM; i++) + seqStorePtr->rep[i] = repToConfirm[i]; + + /* Fill tables for block compressor */ + ZSTD_ldm_limitTableUpdate(cctx, anchor); + ZSTD_ldm_fillFastTables(cctx, anchor); + + /* Call block compressor and get remaining literals */ + lastLiterals = blockCompressor(cctx, anchor, ip - anchor); + cctx->nextToUpdate = (U32)(ip - base); + + /* Update repToConfirm with the new offset */ + for (i = ZSTD_REP_NUM - 1; i > 0; i--) + repToConfirm[i] = repToConfirm[i-1]; + repToConfirm[0] = offset; + + /* Store the sequence with the leftover literals */ + ZSTD_storeSeq(seqStorePtr, lastLiterals, ip - lastLiterals, + offset + ZSTD_REP_MOVE, mLength - MINMATCH); + } + + /* Insert the current entry into the hash table */ + ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, + (U32)(lastHashed - base)); + + assert(ip + backwardMatchLength == lastHashed); + + /* Fill the hash table from lastHashed+1 to ip+mLength*/ + /* Heuristic: don't need to fill the entire table at end of block */ + if (ip + mLength < ilimit) { + rollingHash = ZSTD_ldm_fillLdmHashTable( + ldmState, rollingHash, lastHashed, + ip + mLength, base, hBits); + lastHashed = ip + mLength - 1; + } + ip += mLength; + anchor = ip; + + /* Check immediate repcode */ + while ( (ip < ilimit) + && ( (repToConfirm[1] > 0) + && (MEM_read32(ip) == MEM_read32(ip - repToConfirm[1])) )) { + + size_t const rLength = ZSTD_count(ip+4, ip+4-repToConfirm[1], + iend) + 4; + /* Swap repToConfirm[1] <=> repToConfirm[0] */ + { + U32 const tmpOff = repToConfirm[1]; + repToConfirm[1] = repToConfirm[0]; + repToConfirm[0] = tmpOff; + } + + ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH); + + /* Fill the hash table from lastHashed+1 to ip+rLength*/ + if (ip + rLength < ilimit) { + rollingHash = ZSTD_ldm_fillLdmHashTable( + ldmState, rollingHash, lastHashed, + ip + rLength, base, hBits); + lastHashed = ip + rLength - 1; + } + ip += rLength; + anchor = ip; + + continue; /* faster when present ... (?) */ + } + } + + /* Overwrite rep */ + for (i = 0; i < ZSTD_REP_NUM; i++) + seqStorePtr->rep[i] = repToConfirm[i]; + + ZSTD_ldm_limitTableUpdate(cctx, anchor); + ZSTD_ldm_fillFastTables(cctx, anchor); + + lastLiterals = blockCompressor(cctx, anchor, iend - anchor); + cctx->nextToUpdate = (U32)(ip - base); + + /* Restore seqStorePtr->rep */ + for (i = 0; i < ZSTD_REP_NUM; i++) + seqStorePtr->rep[i] = savedRep[i]; + + /* Return the last literals size */ + return lastLiterals; +} + +static size_t ZSTD_compressBlock_ldm(ZSTD_CCtx* ctx, + const void* src, size_t srcSize) +{ + return ZSTD_compressBlock_ldm_generic(ctx, src, srcSize); +} + +static size_t ZSTD_compressBlock_ldm_extDict_generic( + ZSTD_CCtx* ctx, + const void* src, size_t srcSize) +{ + ldmState_t* ldmState = &(ctx->ldmState); + const U32 hBits = ldmState->hashLog - ldmState->bucketLog; + const U32 ldmBucketSize = (1 << ldmState->bucketLog); + const U32 ldmTagMask = (1 << ldmState->hashEveryLog) - 1; + seqStore_t* const seqStorePtr = &(ctx->seqStore); + const BYTE* const base = ctx->base; + const BYTE* const dictBase = ctx->dictBase; + const BYTE* const istart = (const BYTE*)src; + const BYTE* ip = istart; + const BYTE* anchor = istart; + const U32 lowestIndex = ctx->lowLimit; + const BYTE* const dictStart = dictBase + lowestIndex; + const U32 dictLimit = ctx->dictLimit; + const BYTE* const lowPrefixPtr = base + dictLimit; + const BYTE* const dictEnd = dictBase + dictLimit; + const BYTE* const iend = istart + srcSize; + const BYTE* const ilimit = iend - LDM_MIN_MATCH_LENGTH; + + const ZSTD_blockCompressor blockCompressor = + ZSTD_selectBlockCompressor(ctx->appliedParams.cParams.strategy, 1); + U32* const repToConfirm = seqStorePtr->repToConfirm; + U32 savedRep[ZSTD_REP_NUM]; + U64 rollingHash = 0; + const BYTE* lastHashed = NULL; + size_t i, lastLiterals; + + /* Save seqStorePtr->rep and copy repToConfirm */ + for (i = 0; i < ZSTD_REP_NUM; i++) { + savedRep[i] = repToConfirm[i] = seqStorePtr->rep[i]; + } + + /* Search Loop */ + while (ip < ilimit) { /* < instead of <=, because (ip+1) */ + size_t mLength; + const U32 current = (U32)(ip-base); + size_t forwardMatchLength = 0, backwardMatchLength = 0; + ldmEntry_t* bestEntry = NULL; + if (ip != istart) { + rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0], + lastHashed[LDM_MIN_MATCH_LENGTH]); + } else { + rollingHash = ZSTD_ldm_getRollingHash(ip, LDM_MIN_MATCH_LENGTH); + } + lastHashed = ip; + + if (ZSTD_ldm_getTag(rollingHash, hBits, ldmState->hashEveryLog) != + ldmTagMask) { + /* Don't insert and don't look for a match */ + ip++; + continue; + } + + /* Get the best entry and compute the match lengths */ + { + ldmEntry_t* const bucket = + ZSTD_ldm_getBucket(ldmState, + ZSTD_ldm_getSmallHash(rollingHash, hBits)); + ldmEntry_t* cur; + size_t bestMatchLength = 0; + U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); + + for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) { + const BYTE* const curMatchBase = + cur->offset < dictLimit ? dictBase : base; + const BYTE* const pMatch = curMatchBase + cur->offset; + const BYTE* const matchEnd = + cur->offset < dictLimit ? dictEnd : iend; + const BYTE* const lowMatchPtr = + cur->offset < dictLimit ? dictStart : lowPrefixPtr; + size_t curForwardMatchLength, curBackwardMatchLength, + curTotalMatchLength; + + if (cur->checksum != checksum || cur->offset <= lowestIndex) { + continue; + } + + curForwardMatchLength = ZSTD_count_2segments( + ip, pMatch, iend, + matchEnd, lowPrefixPtr); + if (curForwardMatchLength < LDM_MIN_MATCH_LENGTH) { + continue; + } + curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch( + ip, anchor, pMatch, lowMatchPtr); + curTotalMatchLength = curForwardMatchLength + + curBackwardMatchLength; + + if (curTotalMatchLength > bestMatchLength) { + bestMatchLength = curTotalMatchLength; + forwardMatchLength = curForwardMatchLength; + backwardMatchLength = curBackwardMatchLength; + bestEntry = cur; + } + } + } + + /* No match found -- continue searching */ + if (bestEntry == NULL) { + ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, + (U32)(lastHashed - base)); + ip++; + continue; + } + + /* Match found */ + mLength = forwardMatchLength + backwardMatchLength; + ip -= backwardMatchLength; + + /* Call the block compressor on the remaining literals */ + { + U32 const matchIndex = bestEntry->offset; + U32 const offset = current - matchIndex; + + /* Overwrite rep codes */ + for (i = 0; i < ZSTD_REP_NUM; i++) + seqStorePtr->rep[i] = repToConfirm[i]; + + /* Fill the hash table for the block compressor */ + ZSTD_ldm_limitTableUpdate(ctx, anchor); + ZSTD_ldm_fillFastTables(ctx, anchor); + + /* Call block compressor and get remaining literals */ + lastLiterals = blockCompressor(ctx, anchor, ip - anchor); + ctx->nextToUpdate = (U32)(ip - base); + + /* Update repToConfirm with the new offset */ + for (i = ZSTD_REP_NUM - 1; i > 0; i--) + repToConfirm[i] = repToConfirm[i-1]; + repToConfirm[0] = offset; + + /* Store the sequence with the leftover literals */ + ZSTD_storeSeq(seqStorePtr, lastLiterals, ip - lastLiterals, + offset + ZSTD_REP_MOVE, mLength - MINMATCH); + } + + /* Insert the current entry into the hash table */ + ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, + (U32)(lastHashed - base)); + + /* Fill the hash table from lastHashed+1 to ip+mLength */ + assert(ip + backwardMatchLength == lastHashed); + if (ip + mLength < ilimit) { + rollingHash = ZSTD_ldm_fillLdmHashTable( + ldmState, rollingHash, lastHashed, + ip + mLength, base, hBits); + lastHashed = ip + mLength - 1; + } + ip += mLength; + anchor = ip; + + /* check immediate repcode */ + while (ip < ilimit) { + U32 const current2 = (U32)(ip-base); + U32 const repIndex2 = current2 - repToConfirm[1]; + const BYTE* repMatch2 = repIndex2 < dictLimit ? + dictBase + repIndex2 : base + repIndex2; + if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & + (repIndex2 > lowestIndex)) /* intentional overflow */ + && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { + const BYTE* const repEnd2 = repIndex2 < dictLimit ? + dictEnd : iend; + size_t const repLength2 = + ZSTD_count_2segments(ip+4, repMatch2+4, iend, + repEnd2, lowPrefixPtr) + 4; + + U32 tmpOffset = repToConfirm[1]; + repToConfirm[1] = repToConfirm[0]; + repToConfirm[0] = tmpOffset; + + ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH); + + /* Fill the hash table from lastHashed+1 to ip+repLength2*/ + if (ip + repLength2 < ilimit) { + rollingHash = ZSTD_ldm_fillLdmHashTable( + ldmState, rollingHash, lastHashed, + ip + repLength2, base, hBits); + lastHashed = ip + repLength2 - 1; + } + ip += repLength2; + anchor = ip; + continue; + } + break; + } + } + + /* Overwrite rep */ + for (i = 0; i < ZSTD_REP_NUM; i++) + seqStorePtr->rep[i] = repToConfirm[i]; + + ZSTD_ldm_limitTableUpdate(ctx, anchor); + ZSTD_ldm_fillFastTables(ctx, anchor); + + /* Call the block compressor one last time on the last literals */ + lastLiterals = blockCompressor(ctx, anchor, iend - anchor); + ctx->nextToUpdate = (U32)(ip - base); + + /* Restore seqStorePtr->rep */ + for (i = 0; i < ZSTD_REP_NUM; i++) + seqStorePtr->rep[i] = savedRep[i]; + + /* Return the last literals size */ + return lastLiterals; +} + +static size_t ZSTD_compressBlock_ldm_extDict(ZSTD_CCtx* ctx, + const void* src, size_t srcSize) +{ + return ZSTD_compressBlock_ldm_extDict_generic(ctx, src, srcSize); +} + +static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr, + const BYTE* anchor, size_t lastLLSize) +{ + memcpy(seqStorePtr->lit, anchor, lastLLSize); + seqStorePtr->lit += lastLLSize; +} static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, zc->lowLimit < zc->dictLimit); const BYTE* const base = zc->base; const BYTE* const istart = (const BYTE*)src; const U32 current = (U32)(istart-base); + size_t lastLLSize; + const BYTE* anchor; + const ZSTD_blockCompressor blockCompressor = + zc->ldmState.ldmEnable ? + (zc->lowLimit < zc->dictLimit ? ZSTD_compressBlock_ldm_extDict : + ZSTD_compressBlock_ldm) : + ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, + zc->lowLimit < zc->dictLimit); + if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */ ZSTD_resetSeqStore(&(zc->seqStore)); if (current > zc->nextToUpdate + 384) zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384)); /* limited update after finding a very long match */ - blockCompressor(zc, src, srcSize); + + lastLLSize = blockCompressor(zc, src, srcSize); + + /* Last literals */ + anchor = (const BYTE*)src + srcSize - lastLLSize; + ZSTD_storeLastLiterals(&zc->seqStore, anchor, lastLLSize); + return ZSTD_compressSequences(&zc->seqStore, zc->entropy, &zc->appliedParams.cParams, dst, dstCapacity, srcSize); } @@ -3203,7 +3928,6 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t case ZSTD_fast: ZSTD_fillHashTable (zc, iend, zc->appliedParams.cParams.searchLength); break; - case ZSTD_dfast: ZSTD_fillDoubleHashTable (zc, iend, zc->appliedParams.cParams.searchLength); break; diff --git a/lib/compress/zstd_opt.h b/lib/compress/zstd_opt.h index 53e806eb7..575cfa661 100644 --- a/lib/compress/zstd_opt.h +++ b/lib/compress/zstd_opt.h @@ -413,8 +413,9 @@ static U32 ZSTD_BtGetAllMatches_selectMLS_extDict ( * Optimal parser *********************************/ FORCE_INLINE -void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, - const void* src, size_t srcSize, const int ultra) +size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, + const void* src, size_t srcSize, + const int ultra) { seqStore_t* seqStorePtr = &(ctx->seqStore); optState_t* optStatePtr = &(ctx->optState); @@ -654,17 +655,15 @@ _storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */ /* Save reps for next block */ { int i; for (i=0; irepToConfirm[i] = rep[i]; } - /* Last Literals */ - { size_t const lastLLSize = iend - anchor; - memcpy(seqStorePtr->lit, anchor, lastLLSize); - seqStorePtr->lit += lastLLSize; - } + /* Return the last literals size */ + return iend - anchor; } FORCE_INLINE -void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, - const void* src, size_t srcSize, const int ultra) +size_t ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, + const void* src, size_t srcSize, + const int ultra) { seqStore_t* seqStorePtr = &(ctx->seqStore); optState_t* optStatePtr = &(ctx->optState); @@ -928,11 +927,8 @@ _storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */ /* Save reps for next block */ { int i; for (i=0; irepToConfirm[i] = rep[i]; } - /* Last Literals */ - { size_t lastLLSize = iend - anchor; - memcpy(seqStorePtr->lit, anchor, lastLLSize); - seqStorePtr->lit += lastLLSize; - } + /* Return the last literals size */ + return iend - anchor; } #endif /* ZSTD_OPT_H_91842398743 */ diff --git a/lib/zstd.h b/lib/zstd.h index c11964408..c9fa34f36 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -978,7 +978,9 @@ typedef enum { /* advanced parameters - may not remain available after API update */ ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize, * even when referencing into Dictionary content (default:0) */ - + ZSTD_p_longDistanceMatching, /* Enable long distance matching. + * This increases the memory usage as well as the + * window size. */ } ZSTD_cParameter; diff --git a/programs/bench.c b/programs/bench.c index 7731d079e..a2c4efcf3 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -129,7 +129,10 @@ void BMK_setNbThreads(unsigned nbThreads) { #endif g_nbThreads = nbThreads; } - +static U32 g_ldmFlag = 0; +void BMK_setLdmFlag(unsigned ldmFlag) { + g_ldmFlag = ldmFlag; +} /* ******************************************************** * Bench functions @@ -271,6 +274,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, ZSTD_CCtx_setParameter(ctx, ZSTD_p_searchLog, comprParams->searchLog); ZSTD_CCtx_setParameter(ctx, ZSTD_p_minMatch, comprParams->searchLength); ZSTD_CCtx_setParameter(ctx, ZSTD_p_targetLength, comprParams->targetLength); + ZSTD_CCtx_setParameter(ctx, ZSTD_p_longDistanceMatching, g_ldmFlag); ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionStrategy, comprParams->strategy); ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize); #else diff --git a/programs/bench.h b/programs/bench.h index 77a527f8f..03f56d06b 100644 --- a/programs/bench.h +++ b/programs/bench.h @@ -25,5 +25,6 @@ void BMK_setNbThreads(unsigned nbThreads); void BMK_setNotificationLevel(unsigned level); void BMK_setAdditionalParam(int additionalParam); void BMK_setDecodeOnlyMode(unsigned decodeFlag); +void BMK_setLdmFlag(unsigned ldmFlag); #endif /* BENCH_H_121279284357 */ diff --git a/programs/fileio.c b/programs/fileio.c index 1dd8008e8..8d024a9b3 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -213,6 +213,10 @@ void FIO_setOverlapLog(unsigned overlapLog){ DISPLAYLEVEL(2, "Setting overlapLog is useless in single-thread mode \n"); g_overlapLog = overlapLog; } +static U32 g_ldmFlag = 0; +void FIO_setLdmFlag(unsigned ldmFlag) { + g_ldmFlag = (ldmFlag>0); +} /*-************************************* @@ -407,6 +411,8 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel, CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_minMatch, comprParams->searchLength) ); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_targetLength, comprParams->targetLength) ); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionStrategy, (U32)comprParams->strategy) ); + /* long distance matching */ + CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_longDistanceMatching, g_ldmFlag) ); /* multi-threading */ CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nbThreads, g_nbThreads) ); /* dictionary */ diff --git a/programs/fileio.h b/programs/fileio.h index 9d9167df9..06cf414df 100644 --- a/programs/fileio.h +++ b/programs/fileio.h @@ -56,6 +56,7 @@ void FIO_setMemLimit(unsigned memLimit); void FIO_setNbThreads(unsigned nbThreads); void FIO_setBlockSize(unsigned blockSize); void FIO_setOverlapLog(unsigned overlapLog); +void FIO_setLdmFlag(unsigned ldmFlag); /*-************************************* diff --git a/programs/zstdcli.c b/programs/zstdcli.c index b1268c1f3..cf0710f7c 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -152,6 +152,7 @@ static int usage_advanced(const char* programName) #endif DISPLAY( " -M# : Set a memory usage limit for decompression \n"); DISPLAY( "--list : list information about a zstd compressed file \n"); + DISPLAY( "--long : enable long distance matching\n"); DISPLAY( "-- : All arguments after \"--\" are treated as files \n"); #ifndef ZSTD_NODICT DISPLAY( "\n"); @@ -333,7 +334,8 @@ int main(int argCount, const char* argv[]) ultra=0, lastCommand = 0, nbThreads = 1, - setRealTimePrio = 0; + setRealTimePrio = 0, + ldmFlag = 0; unsigned bench_nbSeconds = 3; /* would be better if this value was synchronized from bench */ size_t blockSize = 0; zstd_operation_mode operation = zom_compress; @@ -440,6 +442,7 @@ int main(int argCount, const char* argv[]) #ifdef ZSTD_LZ4COMPRESS if (!strcmp(argument, "--format=lz4")) { suffix = LZ4_EXTENSION; FIO_setCompressionType(FIO_lz4Compression); continue; } #endif + if (!strcmp(argument, "--long")) { ldmFlag = 1; continue; } /* long commands with arguments */ #ifndef ZSTD_NODICT @@ -690,6 +693,7 @@ int main(int argCount, const char* argv[]) BMK_setBlockSize(blockSize); BMK_setNbThreads(nbThreads); BMK_setNbSeconds(bench_nbSeconds); + BMK_setLdmFlag(ldmFlag); BMK_benchFiles(filenameTable, filenameIdx, dictFileName, cLevel, cLevelLast, &compressionParams, setRealTimePrio); #endif (void)bench_nbSeconds; @@ -757,6 +761,7 @@ int main(int argCount, const char* argv[]) #ifndef ZSTD_NOCOMPRESS FIO_setNbThreads(nbThreads); FIO_setBlockSize((U32)blockSize); + FIO_setLdmFlag(ldmFlag); if (g_overlapLog!=OVERLAP_LOG_DEFAULT) FIO_setOverlapLog(g_overlapLog); if ((filenameIdx==1) && outFileName) operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel, &compressionParams); diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 439ab39d9..ca67483dd 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -440,8 +440,6 @@ static int basicUnitTests(U32 seed, double compressibility) free(staticDCtxBuffer); } - - /* ZSTDMT simple MT compression test */ DISPLAYLEVEL(4, "test%3i : create ZSTDMT CCtx : ", testNb++); { ZSTDMT_CCtx* mtctx = ZSTDMT_createCCtx(2); @@ -1342,6 +1340,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD dictSize = FUZ_rLogLength(&lseed, dictLog); /* needed also for decompression */ dict = srcBuffer + (FUZ_rand(&lseed) % (srcBufferSize - dictSize)); + if (FUZ_rand(&lseed) & 0xF) { CHECK_Z ( ZSTD_compressBegin_usingDict(refCtx, dict, dictSize, cLevel) ); } else { @@ -1350,6 +1349,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD !(FUZ_rand(&lseed)&3) /* contentChecksumFlag*/, 0 /*NodictID*/ }; /* note : since dictionary is fake, dictIDflag has no impact */ ZSTD_parameters const p = FUZ_makeParams(cPar, fPar); + CHECK_Z ( ZSTD_compressBegin_advanced(refCtx, dict, dictSize, p, 0) ); } CHECK_Z( ZSTD_copyCCtx(ctx, refCtx, 0) ); diff --git a/tests/playTests.sh b/tests/playTests.sh index 77853b1a4..8fb2768c2 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -544,6 +544,15 @@ roundTripTest -g516K 19 # btopt fileRoundTripTest -g500K +$ECHO "\n**** zstd long distance matching round-trip tests **** " +roundTripTest -g0 "2 --long" +roundTripTest -g1000K "1 --long" +roundTripTest -g517K "6 --long" +roundTripTest -g516K "16 --long" +roundTripTest -g518K "19 --long" +fileRoundTripTest -g5M "3 --long" + + if [ -n "$hasMT" ] then $ECHO "\n**** zstdmt round-trip tests **** " @@ -551,6 +560,9 @@ then roundTripTest -g8M "3 -T2" roundTripTest -g8000K "2 --threads=2" fileRoundTripTest -g4M "19 -T2 -B1M" + + $ECHO "\n**** zstdmt long distance matching round-trip tests **** " + roundTripTest -g8M "3 --long -T2" else $ECHO "\n**** no multithreading, skipping zstdmt tests **** " fi @@ -639,6 +651,15 @@ roundTripTest -g6000000000 -P99 1 fileRoundTripTest -g4193M -P99 1 +$ECHO "\n**** zstd long, long distance matching round-trip tests **** " +roundTripTest -g0 "2 --long" +roundTripTest -g270000000 "1 --long" +roundTripTest -g140000000 -P60 "5 --long" +roundTripTest -g70000000 -P70 "8 --long" +roundTripTest -g18000001 -P80 "18 --long" +fileRoundTripTest -g4100M -P99 "1 --long" + + if [ -n "$hasMT" ] then $ECHO "\n**** zstdmt long round-trip tests **** " @@ -646,6 +667,7 @@ then roundTripTest -g6000000000 -P99 "1 -T2" roundTripTest -g1500000000 -P97 "1 -T999" fileRoundTripTest -g4195M -P98 " -T0" + roundTripTest -g1500000000 -P97 "1 --long -T999" else $ECHO "\n**** no multithreading, skipping zstdmt tests **** " fi diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 8be6a5910..3baa10ef0 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1380,6 +1380,8 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_minMatch, cParams.searchLength, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_targetLength, cParams.targetLength, useOpaqueAPI) ); + if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_longDistanceMatching, FUZ_rand(&lseed) & 63) ); + /* unconditionally set, to be sync with decoder */ /* mess with frame parameters */ if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_checksumFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); From 8e298382a897de70ad2c9fc2b138192340fc37de Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 31 Aug 2017 14:30:52 -0700 Subject: [PATCH 079/248] changed target allarch into allzstd allzstd contains only zstd-related tests. allmost = allzstd + zwrapper tests (which require zlib) --- Makefile | 17 +++++++---------- appveyor.yml | 12 ++++++------ programs/Makefile | 1 - 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index 423d0a18b..e8bdcea33 100644 --- a/Makefile +++ b/Makefile @@ -29,15 +29,12 @@ default: lib-release zstd-release all: | allmost examples manual .PHONY: allmost -allmost: - $(MAKE) -C $(ZSTDDIR) all - $(MAKE) -C $(PRGDIR) all - $(MAKE) -C $(TESTDIR) all +allmost: allzstd $(MAKE) -C $(ZWRAPDIR) all #skip zwrapper, can't build that on alternate architectures without the proper zlib installed -.PHONY: allarch -allarch: +.PHONY: allzstd +allzstd: $(MAKE) -C $(ZSTDDIR) all $(MAKE) -C $(PRGDIR) all $(MAKE) -C $(TESTDIR) all @@ -158,16 +155,16 @@ m32build: clean $(MAKE) all32 armbuild: clean - CC=arm-linux-gnueabi-gcc CFLAGS="-Werror" $(MAKE) allarch + CC=arm-linux-gnueabi-gcc CFLAGS="-Werror" $(MAKE) allzstd aarch64build: clean - CC=aarch64-linux-gnu-gcc CFLAGS="-Werror" $(MAKE) allarch + CC=aarch64-linux-gnu-gcc CFLAGS="-Werror" $(MAKE) allzstd ppcbuild: clean - CC=powerpc-linux-gnu-gcc CLAGS="-m32 -Wno-attributes -Werror" $(MAKE) allarch + CC=powerpc-linux-gnu-gcc CLAGS="-m32 -Wno-attributes -Werror" $(MAKE) allzstd ppc64build: clean - CC=powerpc-linux-gnu-gcc CFLAGS="-m64 -Werror" $(MAKE) allarch + CC=powerpc-linux-gnu-gcc CFLAGS="-m64 -Werror" $(MAKE) allzstd armfuzz: clean CC=arm-linux-gnueabi-gcc QEMU_SYS=qemu-arm-static MOREFLAGS="-static" FUZZER_FLAGS=--no-big-tests $(MAKE) -C $(TESTDIR) fuzztest diff --git a/appveyor.yml b/appveyor.yml index 1815563e7..91f117952 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,19 +9,19 @@ - COMPILER: "gcc" HOST: "mingw" PLATFORM: "x64" - SCRIPT: "make allarch && make -C tests test-symbols fullbench-dll fullbench-lib" + SCRIPT: "make allzstd && make -C tests test-symbols fullbench-dll fullbench-lib" ARTIFACT: "true" BUILD: "true" - COMPILER: "gcc" HOST: "mingw" PLATFORM: "x86" - SCRIPT: "make allarch" + SCRIPT: "make allzstd" ARTIFACT: "true" BUILD: "true" - COMPILER: "clang" HOST: "mingw" PLATFORM: "x64" - SCRIPT: "MOREFLAGS='--target=x86_64-w64-mingw32 -Werror -Wconversion -Wno-sign-conversion' make allarch" + SCRIPT: "MOREFLAGS='--target=x86_64-w64-mingw32 -Werror -Wconversion -Wno-sign-conversion' make allzstd" BUILD: "true" - COMPILER: "gcc" @@ -172,15 +172,15 @@ - COMPILER: "gcc" HOST: "mingw" PLATFORM: "x64" - SCRIPT: "make allarch" + SCRIPT: "make allzstd" - COMPILER: "gcc" HOST: "mingw" PLATFORM: "x86" - SCRIPT: "make allarch" + SCRIPT: "make allzstd" - COMPILER: "clang" HOST: "mingw" PLATFORM: "x64" - SCRIPT: "MOREFLAGS='--target=x86_64-w64-mingw32 -Werror -Wconversion -Wno-sign-conversion' make allarch" + SCRIPT: "MOREFLAGS='--target=x86_64-w64-mingw32 -Werror -Wconversion -Wno-sign-conversion' make allzstd" - COMPILER: "visual" HOST: "visual" diff --git a/programs/Makefile b/programs/Makefile index 62b558eeb..5a7c373bf 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -67,7 +67,6 @@ else endif ZSTDLIB_FILES := $(sort $(wildcard $(ZSTD_FILES)) $(wildcard $(ZSTDLEGACY_FILES)) $(wildcard $(ZDICT_FILES))) -ZSTDLIB_OBJ := $(patsubst %.c,%.o,$(ZSTDLIB_FILES)) # Define *.exe as extension for Windows systems ifneq (,$(filter Windows%,$(OS))) From 179b161dc13bd7a1a28c9aac5824c3b65f448f0e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 31 Aug 2017 15:02:14 -0700 Subject: [PATCH 080/248] fixed poolTest needs more dependencies from zstd for custom allocators and error codes --- tests/.gitignore | 1 + tests/Makefile | 23 ++++++++++------------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/tests/.gitignore b/tests/.gitignore index f408a7491..24290195e 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -48,6 +48,7 @@ grillResults.txt _* tmp* *.zst +*.gz result out diff --git a/tests/Makefile b/tests/Makefile index 4bffe9137..f6f3f7534 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -44,10 +44,6 @@ ZSTD_FILES := $(ZSTDDECOMP_FILES) $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES) ZBUFF_FILES := $(ZSTDDIR)/deprecated/*.c ZDICT_FILES := $(ZSTDDIR)/dictBuilder/*.c -ZSTD_OBJ := $(patsubst %.c,%.o, $(wildcard $(ZSTD_FILES)) ) -ZBUFF_OBJ := $(patsubst %.c,%.o, $(wildcard $(ZBUFF_FILES)) ) -ZDICT_OBJ := $(patsubst %.c,%.o, $(wildcard $(ZDICT_FILES)) ) - # Define *.exe as extension for Windows systems ifneq (,$(filter Windows%,$(OS))) @@ -75,7 +71,7 @@ all: fullbench fuzzer zstreamtest paramgrill datagen decodecorpus all32: fullbench32 fuzzer32 zstreamtest32 -allnothread: fullbench fuzzer paramgrill datagen decodecorpus +allnothread: fullbench fuzzer paramgrill datagen decodecorpus dll: fuzzer-dll zstreamtest-dll @@ -89,7 +85,7 @@ zstd-nolegacy: $(MAKE) -C $(PRGDIR) $@ gzstd: - $(MAKE) -C $(PRGDIR) $@ + $(MAKE) -C $(PRGDIR) zstd HAVE_ZLIB=1 fullbench32: CPPFLAGS += -m32 fullbench fullbench32 : CPPFLAGS += $(MULTITHREAD_CPP) @@ -190,8 +186,8 @@ else $(CC) $(FLAGS) $^ -o $@$(EXT) -Wl,-rpath=$(ZSTDDIR) $(ZSTDDIR)/libzstd.so endif -poolTests : poolTests.c $(ZSTDDIR)/common/pool.c $(ZSTDDIR)/common/threading.c - $(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT) +poolTests : poolTests.c $(ZSTDDIR)/common/pool.c $(ZSTDDIR)/common/threading.c $(ZSTDDIR)/common/zstd_common.c $(ZSTDDIR)/common/error_private.c + $(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT) namespaceTest: if $(CC) namespaceTest.c ../lib/common/xxhash.c -o $@ ; then echo compilation should fail; exit 1 ; fi @@ -282,13 +278,13 @@ test-zstd-nolegacy: ZSTD = $(PRGDIR)/zstd-nolegacy test-zstd-nolegacy: zstd-nolegacy zstd-playTests test-gzstd: gzstd - $(PRGDIR)/zstd README.md test-zstd-speed.py - gzip README.md test-zstd-speed.py + $(PRGDIR)/zstd -f README.md test-zstd-speed.py + gzip -f README.md test-zstd-speed.py cat README.md.zst test-zstd-speed.py.gz >zstd_gz.zst cat README.md.gz test-zstd-speed.py.zst >gz_zstd.gz - $(PRGDIR)/zstd -d README.md.gz -o README2.md - $(PRGDIR)/zstd -d README.md.gz test-zstd-speed.py.gz - $(PRGDIR)/zstd -d zstd_gz.zst gz_zstd.gz + $(PRGDIR)/zstd -df README.md.gz -o README2.md + $(PRGDIR)/zstd -df README.md.gz test-zstd-speed.py.gz + $(PRGDIR)/zstd -df zstd_gz.zst gz_zstd.gz $(DIFF) -q zstd_gz gz_zstd echo Hello World ZSTD | $(PRGDIR)/zstd -c - >hello.zst echo Hello World GZIP | gzip -c - >hello.gz @@ -296,6 +292,7 @@ test-gzstd: gzstd cat hello.zst hello.gz hello.txt >hello_zst_gz_txt.gz $(PRGDIR)/zstd -dcf hello.* $(PRGDIR)/zstd -dcf - Date: Thu, 31 Aug 2017 15:02:14 -0700 Subject: [PATCH 081/248] fixed poolTests needs more dependencies from zstd for custom allocators and error codes --- tests/.gitignore | 2 ++ tests/Makefile | 23 ++++++++++------------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/tests/.gitignore b/tests/.gitignore index f408a7491..b16e26e3d 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -21,6 +21,7 @@ symbols legacy decodecorpus pool +poolTests invalidDictionaries # Tmp test directory @@ -48,6 +49,7 @@ grillResults.txt _* tmp* *.zst +*.gz result out diff --git a/tests/Makefile b/tests/Makefile index 4bffe9137..f6f3f7534 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -44,10 +44,6 @@ ZSTD_FILES := $(ZSTDDECOMP_FILES) $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES) ZBUFF_FILES := $(ZSTDDIR)/deprecated/*.c ZDICT_FILES := $(ZSTDDIR)/dictBuilder/*.c -ZSTD_OBJ := $(patsubst %.c,%.o, $(wildcard $(ZSTD_FILES)) ) -ZBUFF_OBJ := $(patsubst %.c,%.o, $(wildcard $(ZBUFF_FILES)) ) -ZDICT_OBJ := $(patsubst %.c,%.o, $(wildcard $(ZDICT_FILES)) ) - # Define *.exe as extension for Windows systems ifneq (,$(filter Windows%,$(OS))) @@ -75,7 +71,7 @@ all: fullbench fuzzer zstreamtest paramgrill datagen decodecorpus all32: fullbench32 fuzzer32 zstreamtest32 -allnothread: fullbench fuzzer paramgrill datagen decodecorpus +allnothread: fullbench fuzzer paramgrill datagen decodecorpus dll: fuzzer-dll zstreamtest-dll @@ -89,7 +85,7 @@ zstd-nolegacy: $(MAKE) -C $(PRGDIR) $@ gzstd: - $(MAKE) -C $(PRGDIR) $@ + $(MAKE) -C $(PRGDIR) zstd HAVE_ZLIB=1 fullbench32: CPPFLAGS += -m32 fullbench fullbench32 : CPPFLAGS += $(MULTITHREAD_CPP) @@ -190,8 +186,8 @@ else $(CC) $(FLAGS) $^ -o $@$(EXT) -Wl,-rpath=$(ZSTDDIR) $(ZSTDDIR)/libzstd.so endif -poolTests : poolTests.c $(ZSTDDIR)/common/pool.c $(ZSTDDIR)/common/threading.c - $(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT) +poolTests : poolTests.c $(ZSTDDIR)/common/pool.c $(ZSTDDIR)/common/threading.c $(ZSTDDIR)/common/zstd_common.c $(ZSTDDIR)/common/error_private.c + $(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT) namespaceTest: if $(CC) namespaceTest.c ../lib/common/xxhash.c -o $@ ; then echo compilation should fail; exit 1 ; fi @@ -282,13 +278,13 @@ test-zstd-nolegacy: ZSTD = $(PRGDIR)/zstd-nolegacy test-zstd-nolegacy: zstd-nolegacy zstd-playTests test-gzstd: gzstd - $(PRGDIR)/zstd README.md test-zstd-speed.py - gzip README.md test-zstd-speed.py + $(PRGDIR)/zstd -f README.md test-zstd-speed.py + gzip -f README.md test-zstd-speed.py cat README.md.zst test-zstd-speed.py.gz >zstd_gz.zst cat README.md.gz test-zstd-speed.py.zst >gz_zstd.gz - $(PRGDIR)/zstd -d README.md.gz -o README2.md - $(PRGDIR)/zstd -d README.md.gz test-zstd-speed.py.gz - $(PRGDIR)/zstd -d zstd_gz.zst gz_zstd.gz + $(PRGDIR)/zstd -df README.md.gz -o README2.md + $(PRGDIR)/zstd -df README.md.gz test-zstd-speed.py.gz + $(PRGDIR)/zstd -df zstd_gz.zst gz_zstd.gz $(DIFF) -q zstd_gz gz_zstd echo Hello World ZSTD | $(PRGDIR)/zstd -c - >hello.zst echo Hello World GZIP | gzip -c - >hello.gz @@ -296,6 +292,7 @@ test-gzstd: gzstd cat hello.zst hello.gz hello.txt >hello_zst_gz_txt.gz $(PRGDIR)/zstd -dcf hello.* $(PRGDIR)/zstd -dcf - Date: Thu, 31 Aug 2017 15:24:17 -0700 Subject: [PATCH 082/248] blind attempt at removing gcc dependency from appveyor's mingw builds, for #815 --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 1815563e7..99fa834b4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,13 +9,13 @@ - COMPILER: "gcc" HOST: "mingw" PLATFORM: "x64" - SCRIPT: "make allarch && make -C tests test-symbols fullbench-dll fullbench-lib" + SCRIPT: "make allarch MOREFLAGS=-static && make -C tests test-symbols fullbench-dll fullbench-lib" ARTIFACT: "true" BUILD: "true" - COMPILER: "gcc" HOST: "mingw" PLATFORM: "x86" - SCRIPT: "make allarch" + SCRIPT: "make allarch MOREFLAGS=-static" ARTIFACT: "true" BUILD: "true" - COMPILER: "clang" From 4299c271323d988c4e76d907f0a6710e2cd959d2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 31 Aug 2017 16:58:47 -0700 Subject: [PATCH 083/248] improved console log of utils.h removed a warning when compiling on Windows --- programs/util.h | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/programs/util.h b/programs/util.h index d6e1dfc20..384dec1bd 100644 --- a/programs/util.h +++ b/programs/util.h @@ -105,13 +105,21 @@ extern "C" { #endif +/*-**************************************** +* Console log +******************************************/ +static int g_utilDisplayLevel; +#define UTIL_DISPLAY(...) fprintf(stderr, __VA_ARGS__) +#define UTIL_DISPLAYLEVEL(l, ...) { if (g_utilDisplayLevel>=l) { UTIL_DISPLAY(__VA_ARGS__); } } + + /*-**************************************** * Time functions ******************************************/ #if defined(_WIN32) /* Windows */ typedef LARGE_INTEGER UTIL_freq_t; typedef LARGE_INTEGER UTIL_time_t; - UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { if (!QueryPerformanceFrequency(ticksPerSecond)) fprintf(stderr, "ERROR: QueryPerformance not present\n"); } + UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { if (!QueryPerformanceFrequency(ticksPerSecond)) UTIL_DISPLAYLEVEL(1, "ERROR: QueryPerformance not present\n"); } UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { QueryPerformanceCounter(x); } UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; } UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; } @@ -284,10 +292,6 @@ UTIL_STATIC void *UTIL_realloc(void *ptr, size_t size) return NULL; } -static int g_utilDisplayLevel; -#define UTIL_DISPLAY(...) fprintf(stderr, __VA_ARGS__) -#define UTIL_DISPLAYLEVEL(l, ...) { if (g_utilDisplayLevel>=l) { UTIL_DISPLAY(__VA_ARGS__); } } - #ifdef _WIN32 # define UTIL_HAS_CREATEFILELIST @@ -309,7 +313,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_ hFile=FindFirstFileA(path, &cFile); if (hFile == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Cannot open directory '%s'\n", dirName); + UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s'\n", dirName); return 0; } free(path); @@ -363,7 +367,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_ int dirLength, fnameLength, pathLength, nbFiles = 0; if (!(dir = opendir(dirName))) { - fprintf(stderr, "Cannot open directory '%s': %s\n", dirName, strerror(errno)); + UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s': %s\n", dirName, strerror(errno)); return 0; } @@ -408,7 +412,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_ } if (errno != 0) { - fprintf(stderr, "readdir(%s) error: %s\n", dirName, strerror(errno)); + UTIL_DISPLAYLEVEL(1, "readdir(%s) error: %s\n", dirName, strerror(errno)); free(*bufStart); *bufStart = NULL; } @@ -421,7 +425,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks) { (void)bufStart; (void)bufEnd; (void)pos; - fprintf(stderr, "Directory %s ignored (compiled without _WIN32 or _POSIX_C_SOURCE)\n", dirName); + UTIL_DISPLAYLEVEL(1, "Directory %s ignored (compiled without _WIN32 or _POSIX_C_SOURCE)\n", dirName); return 0; } From 369c29dd1a953d91e581cf559cf8bd5b002b525f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 31 Aug 2017 18:25:56 -0700 Subject: [PATCH 084/248] fixed impact of merge conflict for longRange --- lib/compress/zstdmt_compress.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 93d4a3cec..20122f359 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -447,8 +447,6 @@ ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem) ZSTDMT_initializeCCtxParameters(&mtctx->params, nbThreads); mtctx->cMem = cMem; mtctx->allJobsCompleted = 1; - mtctx->sectionSize = 0; - mtctx->overlapLog = ZSTDMT_OVERLAPLOG_DEFAULT; mtctx->factory = POOL_create_advanced(nbThreads, 0, cMem); mtctx->jobs = ZSTDMT_allocJobsTable(&nbJobs, cMem); mtctx->jobIDMask = nbJobs - 1; @@ -528,7 +526,7 @@ size_t ZSTDMT_CCtxParam_setMTCtxParameter( params->jobSize = value; return 0; case ZSTDMT_p_overlapSectionLog : - DEBUGLOG(5, "ZSTDMT_p_overlapSectionLog : %u", value); + DEBUGLOG(4, "ZSTDMT_p_overlapSectionLog : %u", value); params->overlapSizeLog = (value >= 9) ? 9 : value; return 0; default : From 0c314cde4b9e0776cfdc690422e99945895c9bec Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 31 Aug 2017 18:28:19 -0700 Subject: [PATCH 085/248] updated zstd API manual for new CCtxParams object --- doc/zstd_manual.html | 133 ++++++++++++++++++++++++++++++------------- 1 file changed, 95 insertions(+), 38 deletions(-) diff --git a/doc/zstd_manual.html b/doc/zstd_manual.html index c166e7258..83b75fd86 100644 --- a/doc/zstd_manual.html +++ b/doc/zstd_manual.html @@ -27,7 +27,8 @@
  • Buffer-less and synchronous inner streaming functions
  • Buffer-less streaming compression (synchronous mode)
  • Buffer-less streaming decompression (synchronous mode)
  • -
  • Block functions
  • +
  • ZSTD_CCtx_params
  • +
  • Block functions

  • Introduction

    @@ -402,25 +403,29 @@ size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
     


    size_t ZSTD_estimateCCtxSize(int compressionLevel);
    -size_t ZSTD_estimateCCtxSize_advanced(ZSTD_compressionParameters cParams);
    +size_t ZSTD_estimateCCtxSize_advanced_usingCParams(ZSTD_compressionParameters cParams);
    +size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params);
     size_t ZSTD_estimateDCtxSize(void);
     

    These functions make it possible to estimate memory usage of a future {D,C}Ctx, before its creation. ZSTD_estimateCCtxSize() will provide a budget large enough for any compression level up to selected one. It will also consider src size to be arbitrarily "large", which is worst case. - If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced() can provide a tighter estimation. - ZSTD_estimateCCtxSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced_usingCParams() can provide a tighter estimation. + ZSTD_estimateCCtxSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + ZSTD_estimateCCtxSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1. Note : CCtx estimation is only correct for single-threaded compression


    size_t ZSTD_estimateCStreamSize(int compressionLevel);
    -size_t ZSTD_estimateCStreamSize_advanced(ZSTD_compressionParameters cParams);
    +size_t ZSTD_estimateCStreamSize_advanced_usingCParams(ZSTD_compressionParameters cParams);
    +size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params);
     size_t ZSTD_estimateDStreamSize(size_t windowSize);
     size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
     

    ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one. It will also consider src size to be arbitrarily "large", which is worst case. - If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced() can provide a tighter estimation. - ZSTD_estimateCStreamSize_advanced() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced_usingCParams() can provide a tighter estimation. + ZSTD_estimateCStreamSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + ZSTD_estimateCStreamSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1. Note : CStream estimation is only correct for single-threaded compression. ZSTD_DStream memory budget depends on window Size. This information can be passed manually, using ZSTD_estimateDStreamSize, @@ -430,12 +435,18 @@ size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); In this case, get total size by adding ZSTD_estimate?DictSize


    +
    typedef enum {
    +    ZSTD_dlm_byCopy = 0,      /* Copy dictionary content internally. */
    +    ZSTD_dlm_byRef,           /* Reference dictionary content -- the dictionary buffer must outlives its users. */
    +} ZSTD_dictLoadMethod_e;
    +

    size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel);
    -size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference);
    -size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference);
    +size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod);
    +size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod);
     

    ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). - ZSTD_estimateCStreamSize_advanced() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced(). - Note : dictionary created "byReference" are smaller + ZSTD_estimateCStreamSize_advanced_usingCParams() makes it possible to control precisely compression parameters, like ZSTD_createCDict_advanced(). + Note : dictionary created by reference using ZSTD_dlm_byRef are smaller +


    Advanced compression functions

    
    @@ -461,16 +472,6 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference);
      
     


    -
    typedef enum {
    -    ZSTD_p_forceWindow,   /* Force back-references to remain < windowSize, even when referencing Dictionary content (default:0) */
    -    ZSTD_p_forceRawDict   /* Force loading dictionary in "content-only" mode (no header analysis) */
    -} ZSTD_CCtxParameter;
    -

    -
    size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value);
    -

    Set advanced parameters, selected through enum ZSTD_CCtxParameter - @result : 0, or an error code (which can be tested with ZSTD_isError()) -


    -
    ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel);
     

    Create a digested dictionary for compression Dictionary content is simply referenced, and therefore stays in dictBuffer. @@ -483,7 +484,8 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference); } ZSTD_dictMode_e;


    ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize,
    -                                      unsigned byReference, ZSTD_dictMode_e dictMode,
    +                                      ZSTD_dictLoadMethod_e dictLoadMethod,
    +                                      ZSTD_dictMode_e dictMode,
                                           ZSTD_compressionParameters cParams,
                                           ZSTD_customMem customMem);
     

    Create a ZSTD_CDict using external alloc and free, and customized compression parameters @@ -492,7 +494,7 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference);

    ZSTD_CDict* ZSTD_initStaticCDict(
                     void* workspace, size_t workspaceSize,
               const void* dict, size_t dictSize,
    -                unsigned byReference, ZSTD_dictMode_e dictMode,
    +                ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode,
                     ZSTD_compressionParameters cParams);
     

    Generate a digested dictionary in provided memory area. workspace: The memory area to emplace the dictionary into. @@ -580,13 +582,14 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference);


    ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
    -                                      unsigned byReference, ZSTD_customMem customMem);
    +                                      ZSTD_dictLoadMethod_e dictLoadMethod,
    +                                      ZSTD_customMem customMem);
     

    Create a ZSTD_DDict using external alloc and free, optionally by reference


    ZSTD_DDict* ZSTD_initStaticDDict(void* workspace, size_t workspaceSize,
                                      const void* dict, size_t dictSize,
    -                                 unsigned byReference);
    +                                 ZSTD_dictLoadMethod_e dictLoadMethod);
     

    Generate a digested dictionary in provided memory area. workspace: The memory area to emplace the dictionary into. Provided pointer must 8-bytes aligned. @@ -628,9 +631,9 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, unsigned byReference);

    Advanced Streaming compression functions

    ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem);
     ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize);    /**< same as ZSTD_initStaticCCtx() */
     size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize);   /**< pledgedSrcSize must be correct, a size of 0 means unknown.  for a frame size of 0 use initCStream_advanced */
    -size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. */
    +size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. Note: dict is loaded with ZSTD_dm_auto (treated as a full zstd dictionary if it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.*/
     size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize,
    -                                             ZSTD_parameters params, unsigned long long pledgedSrcSize);  /**< pledgedSrcSize is optional and can be 0 (meaning unknown). note: if the contentSizeFlag is set, pledgedSrcSize == 0 means the source size is actually 0 */
    +                                             ZSTD_parameters params, unsigned long long pledgedSrcSize);  /**< pledgedSrcSize is optional and can be 0 (meaning unknown). note: if the contentSizeFlag is set, pledgedSrcSize == 0 means the source size is actually 0. dict is loaded with ZSTD_dm_auto and ZSTD_dlm_byCopy. */
     size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict);  /**< note : cdict will just be referenced, and must outlive compression session */
     size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize);  /**< same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
     

    @@ -819,12 +822,6 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); ZSTD_p_checksumFlag, /* A 32-bits checksum of content is written at end of frame (default:0) */ ZSTD_p_dictIDFlag, /* When applicable, dictID of dictionary is provided in frame header (default:1) */ - /* dictionary parameters (must be set before ZSTD_CCtx_loadDictionary) */ - ZSTD_p_dictMode=300, /* Select how dictionary content must be interpreted. Value must be from type ZSTD_dictMode_e. - * default : 0==auto : dictionary will be "full" if it respects specification, otherwise it will be "rawContent" */ - ZSTD_p_refDictContent, /* Dictionary content will be referenced, instead of copied (default:0==byCopy). - * It requires that dictionary buffer outlives its users */ - /* multi-threading parameters */ ZSTD_p_nbThreads=400, /* Select how many threads a compression job can spawn (default:1) * More threads improve speed, but also increase memory usage. @@ -861,18 +858,25 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx);


    size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
    +size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
    +size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode);
     

    Create an internal CDict from dict buffer. Decompression will have to use same buffer. @result : 0, or an error code (which can be tested with ZSTD_isError()). Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary, meaning "return to no-dictionary mode". - Note 1 : `dict` content will be copied internally, - except if ZSTD_p_refDictContent is set before loading. + Note 1 : `dict` content will be copied internally. Use + ZSTD_CCtx_loadDictionary_byReference() to reference dictionary + content instead. The dictionary buffer must then outlive its + users. Note 2 : Loading a dictionary involves building tables, which are dependent on compression parameters. For this reason, compression parameters cannot be changed anymore after loading a dictionary. It's also a CPU-heavy operation, with non-negligible impact on latency. Note 3 : Dictionary will be used for all future compression jobs. - To return to "no-dictionary" situation, load a NULL dictionary + To return to "no-dictionary" situation, load a NULL dictionary + Note 5 : Use ZSTD_CCtx_loadDictionary_advanced() to select how dictionary + content will be interpreted. +


    size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
    @@ -889,6 +893,7 @@ void   ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx);
     


    size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize);
    +size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode);
     

    Reference a prefix (single-usage dictionary) for next compression job. Decompression need same prefix to properly regenerate data. Prefix is **only used once**. Tables are discarded at end of compression job. @@ -899,7 +904,9 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); Note 1 : Prefix buffer is referenced. It must outlive compression job. Note 2 : Referencing a prefix involves building tables, which are dependent on compression parameters. It's a CPU-heavy operation, with non-negligible impact on latency. - Note 3 : it's possible to alter ZSTD_p_dictMode using ZSTD_CCtx_setParameter() + Note 3 : By default, the prefix is treated as raw content + (ZSTD_dm_rawContent). Use ZSTD_CCtx_refPrefix_advanced() to alter + dictMode.


    typedef enum {
    @@ -949,7 +956,57 @@ void   ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx);
      
     


    -

    Block functions

    +

    ZSTD_CCtx_params

    +  - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure
    +  - ZSTD_CCtxParam_setParameter() : Push parameters one by one into an
    +  existing ZSTD_CCtx_params structure. This is similar to
    +  ZSTD_CCtx_setParameter().
    +  - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to an existing CCtx. These
    +  parameters will be applied to all subsequent compression jobs.
    +  - ZSTD_compress_generic() : Do compression using the CCtx.
    +  - ZSTD_freeCCtxParams() : Free the memory.
    +
    +  This can be used with ZSTD_estimateCCtxSize_opaque() for static allocation
    +  for single-threaded compression.
    + 
    +
    + +
    size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params);
    +

    Reset params to default, with the default compression level. + +


    + +
    size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, int compressionLevel);
    +

    Initializes the compression parameters of cctxParams according to + compression level. All other parameters are reset to their default values. + +


    + +
    size_t ZSTD_initCCtxParams_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params);
    +

    Initializes the compression and frame parameters of cctxParams according to + params. All other parameters are reset to their default values. + +


    + +
    size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value);
    +

    Similar to ZSTD_CCtx_setParameter. + Set one compression parameter, selected by enum ZSTD_cParameter. + Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams(). + Note : when `value` is an enum, cast it to unsigned for proper type checking. + @result : 0, or an error code (which can be tested with ZSTD_isError()). + +


    + +
    size_t ZSTD_CCtx_setParametersUsingCCtxParams(
    +        ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
    +

    Apply a set of ZSTD_CCtx_params to the compression context. + This must be done before the dictionary is loaded. + The pledgedSrcSize is treated as unknown. + Multithreading parameters are applied only if nbThreads > 1. + +


    + +

    Block functions

         Block functions produce and decode raw zstd blocks, without frame metadata.
         Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
         User will have to take in charge required information to regenerate data, such as compressed and content sizes.
    
    From 370450777403067fe756d4f3b5a80f11bc4ddebf Mon Sep 17 00:00:00 2001
    From: Yann Collet 
    Date: Fri, 1 Sep 2017 00:05:37 -0700
    Subject: [PATCH 086/248] fixed decompression bug reported by @Etsukata (#828)
    
    ---
     lib/decompress/zstd_decompress.c | 34 ++++++++++++++------------------
     1 file changed, 15 insertions(+), 19 deletions(-)
    
    diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c
    index 8e82d85a2..436f817a7 100644
    --- a/lib/decompress/zstd_decompress.c
    +++ b/lib/decompress/zstd_decompress.c
    @@ -1088,7 +1088,10 @@ static size_t ZSTD_decompressSequences(
     }
     
     
    -FORCE_INLINE_TEMPLATE seq_t ZSTD_decodeSequenceLong_generic(seqState_t* seqState, int const longOffsets)
    +typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e;
    +
    +HINT_INLINE
    +seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const longOffsets)
     {
         seq_t seq;
     
    @@ -1180,19 +1183,12 @@ FORCE_INLINE_TEMPLATE seq_t ZSTD_decodeSequenceLong_generic(seqState_t* seqState
         return seq;
     }
     
    -static seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, unsigned const windowSize) {
    -    if (ZSTD_highbit32(windowSize) > STREAM_ACCUMULATOR_MIN) {
    -        return ZSTD_decodeSequenceLong_generic(seqState, 1);
    -    } else {
    -        return ZSTD_decodeSequenceLong_generic(seqState, 0);
    -    }
    -}
     
     HINT_INLINE
     size_t ZSTD_execSequenceLong(BYTE* op,
    -                                BYTE* const oend, seq_t sequence,
    -                                const BYTE** litPtr, const BYTE* const litLimit,
    -                                const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd)
    +                             BYTE* const oend, seq_t sequence,
    +                             const BYTE** litPtr, const BYTE* const litLimit,
    +                             const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd)
     {
         BYTE* const oLitEnd = op + sequence.litLength;
         size_t const sequenceLength = sequence.litLength + sequence.matchLength;
    @@ -1202,11 +1198,9 @@ size_t ZSTD_execSequenceLong(BYTE* op,
         const BYTE* match = sequence.match;
     
         /* check */
    -#if 1
         if (oMatchEnd>oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
         if (iLitEnd > litLimit) return ERROR(corruption_detected);   /* over-read beyond lit buffer */
         if (oLitEnd>oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, base, vBase, dictEnd);
    -#endif
     
         /* copy Literals */
         ZSTD_copy8(op, *litPtr);
    @@ -1216,7 +1210,6 @@ size_t ZSTD_execSequenceLong(BYTE* op,
         *litPtr = iLitEnd;   /* update for next sequence */
     
         /* copy Match */
    -#if 1
         if (sequence.offset > (size_t)(oLitEnd - base)) {
             /* offset beyond prefix */
             if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected);
    @@ -1236,8 +1229,8 @@ size_t ZSTD_execSequenceLong(BYTE* op,
                   return sequenceLength;
                 }
         }   }
    -    /* Requirement: op <= oend_w && sequence.matchLength >= MINMATCH */
    -#endif
    +    assert(op <= oend_w);
    +    assert(sequence.matchLength >= MINMATCH);
     
         /* match within prefix */
         if (sequence.offset < 8) {
    @@ -1285,9 +1278,12 @@ static size_t ZSTD_decompressSequencesLong(
         const BYTE* const base = (const BYTE*) (dctx->base);
         const BYTE* const vBase = (const BYTE*) (dctx->vBase);
         const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
    -    unsigned const windowSize32 = (unsigned)dctx->fParams.windowSize;
         int nbSeq;
     
    +    unsigned long long const regularWindowSizeMax = 1ULL << STREAM_ACCUMULATOR_MIN;
    +    ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(dctx->fParams.windowSize >= regularWindowSizeMax);
    +    ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
    +
         /* Build Decoding Tables */
         {   size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, seqSize);
             if (ZSTD_isError(seqHSize)) return seqHSize;
    @@ -1315,13 +1311,13 @@ static size_t ZSTD_decompressSequencesLong(
     
             /* prepare in advance */
             for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && seqNb
    Date: Fri, 1 Sep 2017 00:12:07 -0700
    Subject: [PATCH 087/248] fixed minor warning (empty translation unit)
    
    ---
     lib/common/threading.c | 8 ++------
     1 file changed, 2 insertions(+), 6 deletions(-)
    
    diff --git a/lib/common/threading.c b/lib/common/threading.c
    index 4e47b6b91..a82c975b2 100644
    --- a/lib/common/threading.c
    +++ b/lib/common/threading.c
    @@ -14,12 +14,8 @@
      * This file will hold wrapper for systems, which do not support pthreads
      */
     
    -/* When ZSTD_MULTITHREAD is not defined, this file would become an empty translation unit.
    - * Include some ISO C header code to prevent this and portably avoid related warnings.
    - * (Visual C++: C4206 / GCC: -Wpedantic / Clang: -Wempty-translation-unit)
    - */
    -#include 
    -
    +/* create fake symbol to avoid empty trnaslation unit warning */
    +int g_ZSTD_threading_useles_symbol;
     
     #if defined(ZSTD_MULTITHREAD) && defined(_WIN32)
     
    
    From 663939597932d2a28727107805a3ab24e0a48196 Mon Sep 17 00:00:00 2001
    From: Eiichi Tsukata 
    Date: Fri, 1 Sep 2017 16:31:58 +0900
    Subject: [PATCH 088/248] tests/fuzz: fix make all target names
    
    ---
     tests/fuzz/Makefile | 6 +++++-
     1 file changed, 5 insertions(+), 1 deletion(-)
    
    diff --git a/tests/fuzz/Makefile b/tests/fuzz/Makefile
    index c6327068f..dfb8f1913 100644
    --- a/tests/fuzz/Makefile
    +++ b/tests/fuzz/Makefile
    @@ -48,7 +48,11 @@ LIBFUZZER ?= -lFuzzer
     
     default: all
     
    -all: round_trip simple_decompress
    +all: \
    +	simple_round_trip \
    +	stream_round_trip \
    +	simple_decompress \
    +	stream_decompress
     
     %.o: %.c
     	$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $^ -c -o $@
    
    From 7492e7f1c7b5f8420e268857f374a3d2250de641 Mon Sep 17 00:00:00 2001
    From: Eiichi Tsukata 
    Date: Fri, 1 Sep 2017 16:35:43 +0900
    Subject: [PATCH 089/248] tests/fuzz: change ZSTD_BLOCKSIZE_ABSOLUTEMAX into
     ZSTD_BLOCKSIZE_MAX
    
    ZSTD_BLOCKSIZE_ABSOLUTEMAX is changed at the commit:
    https://github.com/facebook/zstd/commit/fa3671eac7097ce4ae9a1a4c53d2d1486c29d48f
    ---
     tests/fuzz/stream_decompress.c | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/tests/fuzz/stream_decompress.c b/tests/fuzz/stream_decompress.c
    index ae853dc8c..dfd746972 100644
    --- a/tests/fuzz/stream_decompress.c
    +++ b/tests/fuzz/stream_decompress.c
    @@ -20,7 +20,7 @@
     #include "fuzz_helpers.h"
     #include "zstd.h"
     
    -static size_t const kBufSize = ZSTD_BLOCKSIZE_ABSOLUTEMAX;
    +static size_t const kBufSize = ZSTD_BLOCKSIZE_MAX;
     
     static ZSTD_DStream *dstream = NULL;
     static void* buf = NULL;
    
    From 8081becadce1d706b2eb17ebdc278651d4dcf709 Mon Sep 17 00:00:00 2001
    From: Stella Lau 
    Date: Thu, 31 Aug 2017 15:40:16 -0700
    Subject: [PATCH 090/248] Add long distance matching as a CCtxParam
    
    ---
     lib/common/zstd_internal.h     |  7 ++--
     lib/compress/zstd_compress.c   | 73 ++++++++++++++++++++--------------
     lib/compress/zstdmt_compress.c |  2 +
     lib/zstd.h                     |  8 ++--
     programs/bench.c               |  2 +-
     programs/fileio.c              |  7 ++--
     tests/fuzzer.c                 |  5 ++-
     tests/zstreamtest.c            |  2 +-
     8 files changed, 64 insertions(+), 42 deletions(-)
    
    diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h
    index 49b21c2db..4488ac354 100644
    --- a/lib/common/zstd_internal.h
    +++ b/lib/common/zstd_internal.h
    @@ -281,11 +281,10 @@ typedef struct {
     
     typedef struct {
         ldmEntry_t* hashTable;
    -    BYTE* bucketOffsets;
    -    U32 ldmEnable;          /* 1 if enable long distance matching */
    +    BYTE* bucketOffsets;    /* next position in bucket to insert entry */
         U32 hashLog;            /* log size of hashTable */
         U32 bucketLog;          /* log number of buckets, at most 4 */
    -    U32 hashEveryLog;
    +    U32 hashEveryLog;       /* log number of entries to skip */
     } ldmState_t;
     
     typedef struct {
    @@ -313,6 +312,8 @@ struct ZSTD_CCtx_params_s {
         unsigned jobSize;
         unsigned overlapSizeLog;
     
    +    U32 enableLdm;    /* 1 if enable long distance matching */
    +
         /* For use with createCCtxParams() and freeCCtxParams() only */
         ZSTD_customMem customMem;
     
    diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
    index 331b21207..42d23759b 100644
    --- a/lib/compress/zstd_compress.c
    +++ b/lib/compress/zstd_compress.c
    @@ -53,6 +53,7 @@ size_t ZSTD_compressBound(size_t srcSize) {
         return srcSize + (srcSize >> 8) + margin;
     }
     
    +
     /*-*************************************
     *  Sequence storage
     ***************************************/
    @@ -362,14 +363,11 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
             return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
     
         case ZSTD_p_longDistanceMatching:
    -        /* TODO */
             if (cctx->cdict) return ERROR(stage_wrong);
    -        cctx->ldmState.ldmEnable = value>0;
             if (value != 0) {
                 ZSTD_cLevelToCParams(cctx);
    -            cctx->requestedParams.cParams.windowLog = LDM_WINDOW_LOG;
             }
    -        return 0;
    +        return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
     
         default: return ERROR(parameter_unsupported);
         }
    @@ -471,8 +469,12 @@ size_t ZSTD_CCtxParam_setParameter(
             return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_overlapSectionLog, value);
     
         case ZSTD_p_longDistanceMatching :
    -        /* TODO */
    -        return ERROR(parameter_unsupported);
    +        params->enableLdm = value>0;
    +        if (value != 0) {
    +            ZSTD_cLevelToCCtxParams(params);
    +            params->cParams.windowLog = LDM_WINDOW_LOG;
    +        }
    +        return 0;
     
         default: return ERROR(parameter_unsupported);
         }
    @@ -509,6 +511,9 @@ size_t ZSTD_CCtx_setParametersUsingCCtxParams(
                         cctx, ZSTD_p_overlapSizeLog, params->overlapSizeLog) );
         }
     
    +    /* Copy long distance matching parameter */
    +    cctx->requestedParams.enableLdm = params->enableLdm;
    +
         /* customMem is used only for create/free params and can be ignored */
         return 0;
     }
    @@ -675,6 +680,16 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u
         return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
     }
     
    +/* Estimate the space needed for long distance matching tables. */
    +static size_t ZSTD_ldm_getTableSize(U32 ldmHashLog, U32 bucketLog) {
    +    size_t const ldmHSize = ((size_t)1) << ldmHashLog;
    +    size_t const ldmBucketLog =
    +        MIN(bucketLog, LDM_BUCKET_SIZE_LOG_MAX);
    +    size_t const ldmBucketSize =
    +        ((size_t)1) << (ldmHashLog - ldmBucketLog);
    +    return ldmBucketSize + (ldmHSize * (sizeof(ldmEntry_t)));
    +}
    +
     size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params)
     {
         /* Estimate CCtx size is supported for single-threaded compression only. */
    @@ -699,8 +714,10 @@ size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* pa
                     + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
             size_t const optSpace = ((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btultra)) ? optBudget : 0;
     
    -        /* TODO: Long distance matching is not suported */
    -        size_t const ldmSpace = 0;
    +        /* Ldm parameters can not currently be changed */
    +        size_t const ldmSpace = params->enableLdm ?
    +            ZSTD_ldm_getTableSize(LDM_HASH_LOG, LDM_BUCKET_SIZE_LOG) : 0;
    +
             size_t const neededSpace = entropySpace + tableSpace + tokenSpace +
                                        optSpace + ldmSpace;
     
    @@ -762,7 +779,8 @@ static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
     static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
                                      ZSTD_CCtx_params params2)
     {
    -    return ZSTD_equivalentCParams(params1.cParams, params2.cParams);
    +    return ZSTD_equivalentCParams(params1.cParams, params2.cParams) &&
    +           params1.enableLdm == params2.enableLdm;
     }
     
     /*! ZSTD_continueCCtx() :
    @@ -803,9 +821,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
         assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
     
         if (crp == ZSTDcrp_continue) {
    -        /* TODO: For now, reset if long distance matching is enabled */
    -        if (ZSTD_equivalentParams(params, zc->appliedParams) &&
    -            !zc->ldmState.ldmEnable) {
    +        if (ZSTD_equivalentParams(params, zc->appliedParams)) {
                 DEBUGLOG(5, "ZSTD_equivalentParams()==1");
                 zc->entropy->hufCTable_repeatMode = HUF_repeat_none;
                 zc->entropy->offcode_repeatMode = FSE_repeat_none;
    @@ -838,13 +854,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
             size_t const buffInSize = (zbuff==ZSTDb_buffered) ? ((size_t)1 << params.cParams.windowLog) + blockSize : 0;
             void* ptr;
     
    -        size_t const ldmHSize = ((size_t)1) << zc->ldmState.hashLog;
    -        size_t const ldmBucketSize =
    -            ((size_t)1) << (zc->ldmState.hashLog - zc->ldmState.bucketLog);
    -        size_t const ldmPotentialSpace =
    -            ldmBucketSize + (ldmHSize * (sizeof(ldmEntry_t)));
    -        size_t const ldmSpace = zc->ldmState.ldmEnable ?
    -                                    ldmPotentialSpace : 0;
    +        size_t const ldmSpace = params.enableLdm ? ZSTD_ldm_getTableSize(zc->ldmState.hashLog, zc->ldmState.bucketLog) : 0;
     
             /* Check if workSpace is large enough, alloc a new one if needed */
             {   size_t const entropySpace = sizeof(ZSTD_entropyCTables_t);
    @@ -923,8 +933,11 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
             }
     
             /* ldm space */
    -        if (zc->ldmState.ldmEnable) {
    -            if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, ldmSpace);
    +        if (params.enableLdm) {
    +            size_t const ldmHSize = ((size_t)1) << zc->ldmState.hashLog;
    +            size_t const ldmBucketSize =
    +                    ((size_t)1) << (zc->ldmState.hashLog - zc->ldmState.bucketLog);
    +            memset(ptr, 0, ldmSpace);
                 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
                 zc->ldmState.hashTable = (ldmEntry_t*)ptr;
                 ptr = zc->ldmState.hashTable + ldmHSize;
    @@ -1047,7 +1060,7 @@ static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reduce
     /*! ZSTD_ldm_reduceTable() :
      *  reduce table indexes by `reducerValue` */
     static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size,
    -                                U32 const reducerValue)
    +                                 U32 const reducerValue)
     {
         U32 u;
         for (u = 0; u < size; u++) {
    @@ -1069,8 +1082,8 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
         { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
           ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
     
    -    { if (zc->ldmState.ldmEnable) {
    -          U32 const ldmHSize = 1 << LDM_HASH_LOG;
    +    { if (zc->appliedParams.enableLdm) {
    +          U32 const ldmHSize = 1 << zc->ldmState.hashLog;
               ZSTD_ldm_reduceTable(zc->ldmState.hashTable, ldmHSize, reducerValue);
           }
         }
    @@ -1683,6 +1696,7 @@ static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
         }
     }
     
    +
     /*-*************************************
     *  Fast Scan
     ***************************************/
    @@ -1751,6 +1765,7 @@ size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
                 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
                 offset_2 = offset_1;
                 offset_1 = offset;
    +
                 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
             }
     
    @@ -1983,7 +1998,6 @@ size_t ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
                 ip++;
                 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
             } else {
    -
                 U32 offset;
                 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
                     mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
    @@ -3405,7 +3419,7 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
     
             /* Check immediate repcode */
             while ( (ip < ilimit)
    -             && ( (repToConfirm[1] > 0)
    +             && ( (repToConfirm[1] > 0) && (repToConfirm[1] <= (U32)(ip-lowest))
                  && (MEM_read32(ip) == MEM_read32(ip - repToConfirm[1])) )) {
     
                 size_t const rLength = ZSTD_count(ip+4, ip+4-repToConfirm[1],
    @@ -3413,7 +3427,7 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
                 /* Swap repToConfirm[1] <=> repToConfirm[0] */
                 {
                     U32 const tmpOff = repToConfirm[1];
    -                repToConfirm[1] =  repToConfirm[0];
    +                repToConfirm[1] = repToConfirm[0];
                     repToConfirm[0] = tmpOff;
                 }
     
    @@ -3571,6 +3585,8 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
     
             /* Call the block compressor on the remaining literals */
             {
    +            /* ip = current - backwardMatchLength
    +             * The match is at (bestEntry->offset - backwardMatchLength) */
                 U32 const matchIndex = bestEntry->offset;
                 U32 const offset = current - matchIndex;
     
    @@ -3687,7 +3703,7 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCa
         size_t lastLLSize;
         const BYTE* anchor;
         const ZSTD_blockCompressor blockCompressor =
    -        zc->ldmState.ldmEnable ?
    +        zc->appliedParams.enableLdm?
                 (zc->lowLimit < zc->dictLimit ? ZSTD_compressBlock_ldm_extDict :
                                                 ZSTD_compressBlock_ldm) :
                 ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy,
    @@ -4870,7 +4886,6 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
                     cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbThreads, cctx->customMem);
                     if (cctx->mtctx == NULL) return ERROR(memory_allocation);
                 }
    -
                 DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", params.nbThreads);
                 CHECK_F( ZSTDMT_initCStream_internal(
                                  cctx->mtctx,
    diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c
    index 166f99d72..ae4308b86 100644
    --- a/lib/compress/zstdmt_compress.c
    +++ b/lib/compress/zstdmt_compress.c
    @@ -196,6 +196,8 @@ static ZSTD_CCtx_params ZSTDMT_makeJobCCtxParams(ZSTD_CCtx_params const params)
         jobParams.cParams = params.cParams;
         jobParams.fParams = params.fParams;
         jobParams.compressionLevel = params.compressionLevel;
    +
    +    jobParams.enableLdm = params.enableLdm;
         return jobParams;
     }
     
    diff --git a/lib/zstd.h b/lib/zstd.h
    index c9fa34f36..fa2bbf062 100644
    --- a/lib/zstd.h
    +++ b/lib/zstd.h
    @@ -978,9 +978,11 @@ typedef enum {
         /* advanced parameters - may not remain available after API update */
         ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize,
                                   * even when referencing into Dictionary content (default:0) */
    -    ZSTD_p_longDistanceMatching,    /* Enable long distance matching.
    -                                     * This increases the memory usage as well as the
    -                                     * window size. */
    +    ZSTD_p_longDistanceMatching,  /* Enable long distance matching. This
    +                                   * increases the memory usage as well as the
    +                                   * window size. Note: this should be set after
    +                                   * ZSTD_p_compressionLevel and before
    +                                   * ZSTD_p_windowLog. */
     } ZSTD_cParameter;
     
     
    diff --git a/programs/bench.c b/programs/bench.c
    index a2c4efcf3..5901205d9 100644
    --- a/programs/bench.c
    +++ b/programs/bench.c
    @@ -269,12 +269,12 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
     #ifdef ZSTD_NEWAPI
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_nbThreads, g_nbThreads);
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionLevel, cLevel);
    +                    ZSTD_CCtx_setParameter(ctx, ZSTD_p_longDistanceMatching, g_ldmFlag);
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_windowLog, comprParams->windowLog);
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_chainLog, comprParams->chainLog);
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_searchLog, comprParams->searchLog);
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_minMatch, comprParams->searchLength);
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_targetLength, comprParams->targetLength);
    -                    ZSTD_CCtx_setParameter(ctx, ZSTD_p_longDistanceMatching, g_ldmFlag);
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionStrategy, comprParams->strategy);
                         ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize);
     #else
    diff --git a/programs/fileio.c b/programs/fileio.c
    index 8d024a9b3..1d8fb22bf 100644
    --- a/programs/fileio.c
    +++ b/programs/fileio.c
    @@ -402,8 +402,11 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_dictIDFlag, g_dictIDFlag) );
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_checksumFlag, g_checksumFlag) );
                 CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, srcSize) );
    -            /* compression parameters */
    +            /* compression level */
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionLevel, cLevel) );
    +            /* long distance matching */
    +            CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_longDistanceMatching, g_ldmFlag) );
    +            /* compression parameters */
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_windowLog, comprParams->windowLog) );
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_chainLog, comprParams->chainLog) );
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_hashLog, comprParams->hashLog) );
    @@ -411,8 +414,6 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_minMatch, comprParams->searchLength) );
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_targetLength, comprParams->targetLength) );
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionStrategy, (U32)comprParams->strategy) );
    -            /* long distance matching */
    -            CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_longDistanceMatching, g_ldmFlag) );
                 /* multi-threading */
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nbThreads, g_nbThreads) );
                 /* dictionary */
    diff --git a/tests/fuzzer.c b/tests/fuzzer.c
    index ca67483dd..1d11af2e5 100644
    --- a/tests/fuzzer.c
    +++ b/tests/fuzzer.c
    @@ -440,6 +440,8 @@ static int basicUnitTests(U32 seed, double compressibility)
             free(staticDCtxBuffer);
         }
     
    +
    +
         /* ZSTDMT simple MT compression test */
         DISPLAYLEVEL(4, "test%3i : create ZSTDMT CCtx : ", testNb++);
         {   ZSTDMT_CCtx* mtctx = ZSTDMT_createCCtx(2);
    @@ -1340,7 +1342,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
                 dictSize = FUZ_rLogLength(&lseed, dictLog);   /* needed also for decompression */
                 dict = srcBuffer + (FUZ_rand(&lseed) % (srcBufferSize - dictSize));
     
    -
    +            CHECK_Z ( ZSTD_CCtx_setParameter(refCtx, ZSTD_p_longDistanceMatching, FUZ_rand(&lseed)&255) );
                 if (FUZ_rand(&lseed) & 0xF) {
                     CHECK_Z ( ZSTD_compressBegin_usingDict(refCtx, dict, dictSize, cLevel) );
                 } else {
    @@ -1349,7 +1351,6 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
                                                         !(FUZ_rand(&lseed)&3) /* contentChecksumFlag*/,
                                                         0 /*NodictID*/ };   /* note : since dictionary is fake, dictIDflag has no impact */
                     ZSTD_parameters const p = FUZ_makeParams(cPar, fPar);
    -
                     CHECK_Z ( ZSTD_compressBegin_advanced(refCtx, dict, dictSize, p, 0) );
                 }
                 CHECK_Z( ZSTD_copyCCtx(ctx, refCtx, 0) );
    diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c
    index 3baa10ef0..ba86fbcbb 100644
    --- a/tests/zstreamtest.c
    +++ b/tests/zstreamtest.c
    @@ -1380,7 +1380,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
                     if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_minMatch, cParams.searchLength, useOpaqueAPI) );
                     if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_targetLength, cParams.targetLength, useOpaqueAPI) );
     
    -                if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_longDistanceMatching, FUZ_rand(&lseed) & 63) );
    +                if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_longDistanceMatching, FUZ_rand(&lseed) & 63, useOpaqueAPI) );
     
                     /* unconditionally set, to be sync with decoder */
                     /* mess with frame parameters */
    
    From 36aa8b59993e18a8759a11c3302530a715444986 Mon Sep 17 00:00:00 2001
    From: Yann Collet 
    Date: Fri, 1 Sep 2017 11:40:59 -0700
    Subject: [PATCH 091/248] improved decoding speed
    
    ---
     lib/decompress/zstd_decompress.c | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c
    index 436f817a7..bc8f93851 100644
    --- a/lib/decompress/zstd_decompress.c
    +++ b/lib/decompress/zstd_decompress.c
    @@ -1281,7 +1281,7 @@ static size_t ZSTD_decompressSequencesLong(
         int nbSeq;
     
         unsigned long long const regularWindowSizeMax = 1ULL << STREAM_ACCUMULATOR_MIN;
    -    ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(dctx->fParams.windowSize >= regularWindowSizeMax);
    +    ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (dctx->fParams.windowSize >= regularWindowSizeMax));
         ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
     
         /* Build Decoding Tables */
    
    From 0558850735e850e4553366b5be683e130940aba1 Mon Sep 17 00:00:00 2001
    From: Yann Collet 
    Date: Fri, 1 Sep 2017 11:46:15 -0700
    Subject: [PATCH 092/248] bench stops immediately on decoding error
    
    ---
     programs/bench.c | 4 +---
     1 file changed, 1 insertion(+), 3 deletions(-)
    
    diff --git a/programs/bench.c b/programs/bench.c
    index a4321246f..d5c04c698 100644
    --- a/programs/bench.c
    +++ b/programs/bench.c
    @@ -373,10 +373,8 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
                                 blockTable[blockNb].cPtr, blockTable[blockNb].cSize,
                                 ddict);
                             if (ZSTD_isError(regenSize)) {
    -                            DISPLAY("ZSTD_decompress_usingDDict() failed on block %u of size %u : %s  \n",
    +                            EXM_THROW(2, "ZSTD_decompress_usingDDict() failed on block %u of size %u : %s  \n",
                                           blockNb, (U32)blockTable[blockNb].cSize, ZSTD_getErrorName(regenSize));
    -                            clockLoop = 0;   /* force immediate test end */
    -                            break;
                             }
                             blockTable[blockNb].resSize = regenSize;
                         }
    
    From 8a5c0c98ae5a7884694589d7a69bc99011add94d Mon Sep 17 00:00:00 2001
    From: Yann Collet 
    Date: Fri, 1 Sep 2017 11:56:57 -0700
    Subject: [PATCH 093/248] restored 32-bits decoder ability to decode long
     offsets (>32 MB, levels 21+)
    
    ---
     lib/decompress/zstd_decompress.c | 8 ++------
     1 file changed, 2 insertions(+), 6 deletions(-)
    
    diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c
    index bc8f93851..ada773b9a 100644
    --- a/lib/decompress/zstd_decompress.c
    +++ b/lib/decompress/zstd_decompress.c
    @@ -1365,12 +1365,8 @@ static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
             ip += litCSize;
             srcSize -= litCSize;
         }
    -    if (sizeof(size_t) > 4)  /* do not enable prefetching on 32-bits x86, as it's performance detrimental */
    -                             /* likely because of register pressure */
    -                             /* if that's the correct cause, then 32-bits ARM should be affected differently */
    -                             /* it would be good to test this on ARM real hardware, to see if prefetch version improves speed */
    -        if (dctx->fParams.windowSize > (1<<23))
    -            return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize);
    +    if (dctx->fParams.windowSize > (1<<23))
    +        return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize);
         return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize);
     }
     
    
    From ed7ace38e92392eb80c699fbcb457c1ff6576ce1 Mon Sep 17 00:00:00 2001
    From: Yann Collet 
    Date: Fri, 1 Sep 2017 11:58:37 -0700
    Subject: [PATCH 094/248] updated NEWS
    
    fix for 32-bits decoder
    ---
     NEWS | 1 +
     1 file changed, 1 insertion(+)
    
    diff --git a/NEWS b/NEWS
    index 3ee7d0c32..c659e1f47 100644
    --- a/NEWS
    +++ b/NEWS
    @@ -1,6 +1,7 @@
     v1.3.2
     license : changed /examples license to BSD + GPLv2
     license : fix a few header files to reflect new license (#825)
    +fix : 32-bits build can now decode large offsets (levels 21+)
     fix : a rare compression bug when compression generates very large distances (only possible at --ultra -22)
     build: better compatibility with reproducible builds, by Bernhard M. Wiedemann (@bmwiedemann) (#818)
     
    
    From 767a0b3be191475a2f65548679af6734670cc40c Mon Sep 17 00:00:00 2001
    From: Stella Lau 
    Date: Fri, 1 Sep 2017 12:24:59 -0700
    Subject: [PATCH 095/248] Move ldm hashLog, bucketLog, and mml to cctxParams
    
    ---
     lib/common/zstd_internal.h     |  18 +++-
     lib/compress/zstd_compress.c   | 183 ++++++++++++++++++++++-----------
     lib/compress/zstdmt_compress.c |   2 +-
     lib/zstd.h                     |  11 +-
     tests/zstreamtest.c            |   2 +
     5 files changed, 148 insertions(+), 68 deletions(-)
    
    diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h
    index d7404c064..b3d9a6c6e 100644
    --- a/lib/common/zstd_internal.h
    +++ b/lib/common/zstd_internal.h
    @@ -255,12 +255,19 @@ typedef struct {
     
     typedef struct {
         ldmEntry_t* hashTable;
    -    BYTE* bucketOffsets;    /* next position in bucket to insert entry */
    -    U32 hashLog;            /* log size of hashTable */
    -    U32 bucketLog;          /* log number of buckets, at most 4 */
    -    U32 hashEveryLog;       /* log number of entries to skip */
    +    BYTE* bucketOffsets;    /* Next position in bucket to insert entry */
    +    U32 hashEveryLog;       /* Log number of entries to skip */
    +    U64 hashPower;          /* Used to compute the rolling hash.
    +                             * Depends on ldmParams.minMatchLength */
     } ldmState_t;
     
    +typedef struct {
    +    U32 enableLdm;          /* 1 if enable long distance matching */
    +    U32 hashLog;            /* Log size of hashTable */
    +    U32 bucketLog;          /* Log number of buckets, at most 4 */
    +    U32 minMatchLength;     /* Minimum match length */
    +} ldmParams_t;
    +
     typedef struct {
         U32 hufCTable[HUF_CTABLE_SIZE_U32(255)];
         FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
    @@ -286,7 +293,8 @@ struct ZSTD_CCtx_params_s {
         unsigned jobSize;
         unsigned overlapSizeLog;
     
    -    U32 enableLdm;    /* 1 if enable long distance matching */
    +    /* Long distance matching parameters */
    +    ldmParams_t ldmParams;
     
         /* For use with createCCtxParams() and freeCCtxParams() only */
         ZSTD_customMem customMem;
    diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
    index c02ee6cfb..e74787f37 100644
    --- a/lib/compress/zstd_compress.c
    +++ b/lib/compress/zstd_compress.c
    @@ -313,6 +313,16 @@ size_t ZSTDMT_CCtxParam_setMTCtxParameter(
         ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value);
     size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads);
     
    +static size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm)
    +{
    +    assert(LDM_BUCKET_SIZE_LOG <= LDM_BUCKET_SIZE_LOG_MAX);
    +    params->enableLdm = enableLdm>0;
    +    params->hashLog = LDM_HASH_LOG;
    +    params->bucketLog = LDM_BUCKET_SIZE_LOG;
    +    params->minMatchLength = LDM_MIN_MATCH_LENGTH;
    +    return 0;
    +}
    +
     size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value)
     {
         if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
    @@ -369,6 +379,12 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
             }
             return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
     
    +    case ZSTD_p_ldmHashLog:
    +    case ZSTD_p_ldmMinMatch:
    +        if (value == 0) return 0;  /* special value : 0 means "don't change anything" */
    +        if (cctx->cdict) return ERROR(stage_wrong);
    +        return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
    +
         default: return ERROR(parameter_unsupported);
         }
     }
    @@ -469,11 +485,22 @@ size_t ZSTD_CCtxParam_setParameter(
             return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_overlapSectionLog, value);
     
         case ZSTD_p_longDistanceMatching :
    -        params->enableLdm = value>0;
             if (value != 0) {
                 ZSTD_cLevelToCCtxParams(params);
                 params->cParams.windowLog = LDM_WINDOW_LOG;
             }
    +        return ZSTD_ldm_initializeParameters(¶ms->ldmParams, value);
    +
    +    case ZSTD_p_ldmHashLog :
    +        if (value == 0) return 0;
    +        CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
    +        params->ldmParams.hashLog = value;
    +        return 0;
    +
    +    case ZSTD_p_ldmMinMatch :
    +        if (value == 0) return 0;
    +        CLAMPCHECK(value, ZSTD_LDM_SEARCHLENGTH_MIN, ZSTD_LDM_SEARCHLENGTH_MAX);
    +        params->ldmParams.minMatchLength = value;
             return 0;
     
         default: return ERROR(parameter_unsupported);
    @@ -512,7 +539,7 @@ size_t ZSTD_CCtx_setParametersUsingCCtxParams(
         }
     
         /* Copy long distance matching parameter */
    -    cctx->requestedParams.enableLdm = params->enableLdm;
    +    cctx->requestedParams.ldmParams = params->ldmParams;
     
         /* customMem is used only for create/free params and can be ignored */
         return 0;
    @@ -716,8 +743,9 @@ size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* pa
             size_t const optSpace = ((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btultra)) ? optBudget : 0;
     
             /* Ldm parameters can not currently be changed */
    -        size_t const ldmSpace = params->enableLdm ?
    -            ZSTD_ldm_getTableSize(LDM_HASH_LOG, LDM_BUCKET_SIZE_LOG) : 0;
    +        size_t const ldmSpace = params->ldmParams.enableLdm ?
    +            ZSTD_ldm_getTableSize(params->ldmParams.hashLog,
    +                                  params->ldmParams.bucketLog) : 0;
     
             size_t const neededSpace = entropySpace + tableSpace + tokenSpace +
                                        optSpace + ldmSpace;
    @@ -776,12 +804,24 @@ static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
              & ((cParams1.searchLength==3) == (cParams2.searchLength==3));  /* hashlog3 space */
     }
     
    +/** The parameters are equivalent if ldm is not enabled in both sets or
    + *  all the parameters are equivalent. */
    +static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1,
    +                                    ldmParams_t ldmParams2)
    +{
    +    return (!ldmParams1.enableLdm && !ldmParams2.enableLdm) ||
    +           (ldmParams1.enableLdm == ldmParams2.enableLdm &&
    +            ldmParams1.hashLog == ldmParams2.hashLog &&
    +            ldmParams1.bucketLog == ldmParams2.bucketLog &&
    +            ldmParams1.minMatchLength == ldmParams2.minMatchLength);
    +}
    +
     /** Equivalence for resetCCtx purposes */
     static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
                                      ZSTD_CCtx_params params2)
     {
         return ZSTD_equivalentCParams(params1.cParams, params2.cParams) &&
    -           params1.enableLdm == params2.enableLdm;
    +           ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams);
     }
     
     /*! ZSTD_continueCCtx() :
    @@ -812,6 +852,8 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pl
     typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
     typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e;
     
    +static U64 ZSTD_ldm_getHashPower(U32 minMatchLength);
    +
     /*! ZSTD_resetCCtx_internal() :
         note : `params` are assumed fully validated at this stage */
     static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
    @@ -831,13 +873,12 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
                 return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
         }   }
     
    -    {
    -        zc->ldmState.hashLog = LDM_HASH_LOG;
    -        zc->ldmState.bucketLog =
    -            MIN(LDM_BUCKET_SIZE_LOG, LDM_BUCKET_SIZE_LOG_MAX);
    +    if (params.ldmParams.enableLdm) {
             zc->ldmState.hashEveryLog =
    -            params.cParams.windowLog < zc->ldmState.hashLog ?
    -                0 : params.cParams.windowLog - zc->ldmState.hashLog;
    +            params.cParams.windowLog < params.ldmParams.hashLog ?
    +                0 : params.cParams.windowLog - params.ldmParams.hashLog;
    +        zc->ldmState.hashPower =
    +                ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength);
         }
     
         {   size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
    @@ -855,7 +896,9 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
             size_t const buffInSize = (zbuff==ZSTDb_buffered) ? ((size_t)1 << params.cParams.windowLog) + blockSize : 0;
             void* ptr;
     
    -        size_t const ldmSpace = params.enableLdm ? ZSTD_ldm_getTableSize(zc->ldmState.hashLog, zc->ldmState.bucketLog) : 0;
    +        size_t const ldmSpace = params.ldmParams.enableLdm ?
    +                ZSTD_ldm_getTableSize(params.ldmParams.hashLog,
    +                                      params.ldmParams.bucketLog) : 0;
     
             /* Check if workSpace is large enough, alloc a new one if needed */
             {   size_t const entropySpace = sizeof(ZSTD_entropyCTables_t);
    @@ -934,10 +977,10 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
             }
     
             /* ldm space */
    -        if (params.enableLdm) {
    -            size_t const ldmHSize = ((size_t)1) << zc->ldmState.hashLog;
    +        if (params.ldmParams.enableLdm) {
    +            size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
                 size_t const ldmBucketSize =
    -                    ((size_t)1) << (zc->ldmState.hashLog - zc->ldmState.bucketLog);
    +                    ((size_t)1) << (params.ldmParams.hashLog - params.ldmParams.bucketLog);
                 memset(ptr, 0, ldmSpace);
                 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
                 zc->ldmState.hashTable = (ldmEntry_t*)ptr;
    @@ -1083,8 +1126,8 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
         { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
           ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
     
    -    { if (zc->appliedParams.enableLdm) {
    -          U32 const ldmHSize = 1 << zc->ldmState.hashLog;
    +    { if (zc->appliedParams.ldmParams.enableLdm) {
    +          U32 const ldmHSize = 1 << zc->appliedParams.ldmParams.hashLog;
               ZSTD_ldm_reduceTable(zc->ldmState.hashTable, ldmHSize, reducerValue);
           }
         }
    @@ -3094,20 +3137,22 @@ static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits)
     
     /** ZSTD_ldm_getBucket() :
      *  Returns a pointer to the start of the bucket associated with hash. */
    -static ldmEntry_t* ZSTD_ldm_getBucket(ldmState_t* ldmState, size_t hash)
    +static ldmEntry_t* ZSTD_ldm_getBucket(
    +        ldmState_t* ldmState, size_t hash, ldmParams_t const ldmParams)
     {
    -    return ldmState->hashTable + (hash << ldmState->bucketLog);
    +    return ldmState->hashTable + (hash << ldmParams.bucketLog);
     }
     
     /** ZSTD_ldm_insertEntry() :
      *  Insert the entry with corresponding hash into the hash table */
     static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
    -                                 size_t const hash, const ldmEntry_t entry)
    +                                 size_t const hash, const ldmEntry_t entry,
    +                                 ldmParams_t const ldmParams)
     {
         BYTE* const bucketOffsets = ldmState->bucketOffsets;
    -    *(ZSTD_ldm_getBucket(ldmState, hash) + bucketOffsets[hash]) = entry;
    +    *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry;
         bucketOffsets[hash]++;
    -    bucketOffsets[hash] &= (1 << ldmState->bucketLog) - 1;
    +    bucketOffsets[hash] &= (1 << ldmParams.bucketLog) - 1;
     }
     
     /** ZSTD_ldm_makeEntryAndInsertByTag() :
    @@ -3122,7 +3167,8 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
      *  by ldmState->hashEveryLog bits that make up the tag. */
     static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
                                                  U64 rollingHash, U32 hBits,
    -                                             U32 const offset)
    +                                             U32 const offset,
    +                                             ldmParams_t const ldmParams)
     {
         U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmState->hashEveryLog);
         U32 const tagMask = (1 << ldmState->hashEveryLog) - 1;
    @@ -3132,7 +3178,7 @@ static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
             ldmEntry_t entry;
             entry.offset = offset;
             entry.checksum = checksum;
    -        ZSTD_ldm_insertEntry(ldmState, hash, entry);
    +        ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams);
         }
     }
     
    @@ -3170,14 +3216,15 @@ static U64 ZSTD_ldm_ipow(U64 base, U64 exp)
         return ret;
     }
     
    +static U64 ZSTD_ldm_getHashPower(U32 minMatchLength) {
    +    assert(minMatchLength >= ZSTD_LDM_SEARCHLENGTH_MIN);
    +    return ZSTD_ldm_ipow(prime8bytes, minMatchLength - 1);
    +}
    +
     /** ZSTD_ldm_updateHash() :
    - *  Updates hash by removing toRemove and adding toAdd.
    - *
    - *  Note: this currently relies on compiler optimization to avoid
    - *  recalculating hashPower. */
    -static U64 ZSTD_ldm_updateHash(U64 hash, BYTE toRemove, BYTE toAdd)
    + *  Updates hash by removing toRemove and adding toAdd. */
    +static U64 ZSTD_ldm_updateHash(U64 hash, BYTE toRemove, BYTE toAdd, U64 hashPower)
     {
    -    U64 const hashPower = ZSTD_ldm_ipow(prime8bytes, LDM_MIN_MATCH_LENGTH - 1);
         hash -= ((toRemove + LDM_HASH_CHAR_OFFSET) * hashPower);
         hash *= prime8bytes;
         hash += toAdd + LDM_HASH_CHAR_OFFSET;
    @@ -3248,17 +3295,18 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_CCtx* zc, const void* end)
     static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state,
                                          U64 lastHash, const BYTE* lastHashed,
                                          const BYTE* iend, const BYTE* base,
    -                                     U32 hBits)
    +                                     U32 hBits, ldmParams_t const ldmParams)
     {
         U64 rollingHash = lastHash;
         const BYTE* cur = lastHashed + 1;
     
         while (cur < iend) {
             rollingHash = ZSTD_ldm_updateHash(rollingHash, cur[-1],
    -                                          cur[LDM_MIN_MATCH_LENGTH-1]);
    +                                          cur[ldmParams.minMatchLength-1],
    +                                          state->hashPower);
             ZSTD_ldm_makeEntryAndInsertByTag(state,
                                              rollingHash, hBits,
    -                                         (U32)(cur - base));
    +                                         (U32)(cur - base), ldmParams);
             ++cur;
         }
         return rollingHash;
    @@ -3283,9 +3331,9 @@ static void ZSTD_ldm_limitTableUpdate(ZSTD_CCtx* cctx, const BYTE* anchor)
      *
      *  This is a block compressor intended for long distance matching.
      *
    - *  The function searches for matches of length at least LDM_MIN_MATCH_LENGTH
    - *  using a hash table in cctx->ldmState. Matches can be at a distance of
    - *  up to LDM_WINDOW_LOG.
    + *  The function searches for matches of length at least
    + *  ldmParams.minMatchLength using a hash table in cctx->ldmState.
    + *  Matches can be at a distance of up to cParams.windowLog.
      *
      *  Upon finding a match, the unmatched literals are compressed using a
      *  ZSTD_blockCompressor (depending on the strategy in the compression
    @@ -3297,8 +3345,10 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
                                           const void* src, size_t srcSize)
     {
         ldmState_t* const ldmState = &(cctx->ldmState);
    -    const U32 hBits = ldmState->hashLog - ldmState->bucketLog;
    -    const U32 ldmBucketSize = (1 << ldmState->bucketLog);
    +    const ldmParams_t ldmParams = cctx->appliedParams.ldmParams;
    +    const U64 hashPower = ldmState->hashPower;
    +    const U32 hBits = ldmParams.hashLog - ldmParams.bucketLog;
    +    const U32 ldmBucketSize = (1 << ldmParams.bucketLog);
         const U32 ldmTagMask = (1 << ldmState->hashEveryLog) - 1;
         seqStore_t* const seqStorePtr = &(cctx->seqStore);
         const BYTE* const base = cctx->base;
    @@ -3308,7 +3358,7 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
         const U32   lowestIndex = cctx->dictLimit;
         const BYTE* const lowest = base + lowestIndex;
         const BYTE* const iend = istart + srcSize;
    -    const BYTE* const ilimit = iend - LDM_MIN_MATCH_LENGTH;
    +    const BYTE* const ilimit = iend - ldmParams.minMatchLength;
     
         const ZSTD_blockCompressor blockCompressor =
             ZSTD_selectBlockCompressor(cctx->appliedParams.cParams.strategy, 0);
    @@ -3330,9 +3380,10 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
             ldmEntry_t* bestEntry = NULL;
             if (ip != istart) {
                 rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0],
    -                                              lastHashed[LDM_MIN_MATCH_LENGTH]);
    +                                              lastHashed[ldmParams.minMatchLength],
    +                                              hashPower);
             } else {
    -            rollingHash = ZSTD_ldm_getRollingHash(ip, LDM_MIN_MATCH_LENGTH);
    +            rollingHash = ZSTD_ldm_getRollingHash(ip, ldmParams.minMatchLength);
             }
             lastHashed = ip;
     
    @@ -3347,7 +3398,8 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
             {
                 ldmEntry_t* const bucket =
                     ZSTD_ldm_getBucket(ldmState,
    -                                   ZSTD_ldm_getSmallHash(rollingHash, hBits));
    +                                   ZSTD_ldm_getSmallHash(rollingHash, hBits),
    +                                   ldmParams);
                 ldmEntry_t* cur;
                 size_t bestMatchLength = 0;
                 U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
    @@ -3361,7 +3413,7 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
                     }
     
                     curForwardMatchLength = ZSTD_count(ip, pMatch, iend);
    -                if (curForwardMatchLength < LDM_MIN_MATCH_LENGTH) {
    +                if (curForwardMatchLength < ldmParams.minMatchLength) {
                         continue;
                     }
                     curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch(
    @@ -3381,7 +3433,8 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
             /* No match found -- continue searching */
             if (bestEntry == NULL) {
                 ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash,
    -                                             hBits, current);
    +                                             hBits, current,
    +                                             ldmParams);
                 ip++;
                 continue;
             }
    @@ -3420,7 +3473,8 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
     
             /* Insert the current entry into the hash table */
             ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
    -                                         (U32)(lastHashed - base));
    +                                         (U32)(lastHashed - base),
    +                                         ldmParams);
     
             assert(ip + backwardMatchLength == lastHashed);
     
    @@ -3429,12 +3483,11 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
             if (ip + mLength < ilimit) {
                 rollingHash = ZSTD_ldm_fillLdmHashTable(
                                   ldmState, rollingHash, lastHashed,
    -                              ip + mLength, base, hBits);
    +                              ip + mLength, base, hBits, ldmParams);
                 lastHashed = ip + mLength - 1;
             }
             ip += mLength;
             anchor = ip;
    -
             /* Check immediate repcode */
             while ( (ip < ilimit)
                  && ( (repToConfirm[1] > 0) && (repToConfirm[1] <= (U32)(ip-lowest))
    @@ -3455,7 +3508,7 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
                 if (ip + rLength < ilimit) {
                     rollingHash = ZSTD_ldm_fillLdmHashTable(
                                     ldmState, rollingHash, lastHashed,
    -                                ip + rLength, base, hBits);
    +                                ip + rLength, base, hBits, ldmParams);
                     lastHashed = ip + rLength - 1;
                 }
                 ip += rLength;
    @@ -3494,9 +3547,11 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
                                      const void* src, size_t srcSize)
     {
         ldmState_t* ldmState = &(ctx->ldmState);
    -    const U32 hBits = ldmState->hashLog - ldmState->bucketLog;
    -    const U32 ldmBucketSize = (1 << ldmState->bucketLog);
    -    const U32 ldmTagMask = (1 << ldmState->hashEveryLog) - 1;
    +    const ldmParams_t ldmParams = ctx->appliedParams.ldmParams;
    +    const U64 hashPower = ldmState->hashPower;
    +    const U32 hBits = ldmParams.hashLog - ldmParams.bucketLog;
    +    const U32 ldmBucketSize = (1 << ldmParams.bucketLog);
    +    const U32 ldmTagMask = (1 << ctx->ldmState.hashEveryLog) - 1;
         seqStore_t* const seqStorePtr = &(ctx->seqStore);
         const BYTE* const base = ctx->base;
         const BYTE* const dictBase = ctx->dictBase;
    @@ -3509,7 +3564,7 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
         const BYTE* const lowPrefixPtr = base + dictLimit;
         const BYTE* const dictEnd = dictBase + dictLimit;
         const BYTE* const iend = istart + srcSize;
    -    const BYTE* const ilimit = iend - LDM_MIN_MATCH_LENGTH;
    +    const BYTE* const ilimit = iend - ldmParams.minMatchLength;
     
         const ZSTD_blockCompressor blockCompressor =
             ZSTD_selectBlockCompressor(ctx->appliedParams.cParams.strategy, 1);
    @@ -3532,9 +3587,10 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
             ldmEntry_t* bestEntry = NULL;
             if (ip != istart) {
               rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0],
    -                                       lastHashed[LDM_MIN_MATCH_LENGTH]);
    +                                       lastHashed[ldmParams.minMatchLength],
    +                                       hashPower);
             } else {
    -            rollingHash = ZSTD_ldm_getRollingHash(ip, LDM_MIN_MATCH_LENGTH);
    +            rollingHash = ZSTD_ldm_getRollingHash(ip, ldmParams.minMatchLength);
             }
             lastHashed = ip;
     
    @@ -3549,7 +3605,8 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
             {
                 ldmEntry_t* const bucket =
                     ZSTD_ldm_getBucket(ldmState,
    -                                   ZSTD_ldm_getSmallHash(rollingHash, hBits));
    +                                   ZSTD_ldm_getSmallHash(rollingHash, hBits),
    +                                   ldmParams);
                 ldmEntry_t* cur;
                 size_t bestMatchLength = 0;
                 U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
    @@ -3572,7 +3629,7 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
                     curForwardMatchLength = ZSTD_count_2segments(
                                                 ip, pMatch, iend,
                                                 matchEnd, lowPrefixPtr);
    -                if (curForwardMatchLength < LDM_MIN_MATCH_LENGTH) {
    +                if (curForwardMatchLength < ldmParams.minMatchLength) {
                         continue;
                     }
                     curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch(
    @@ -3592,7 +3649,8 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
             /* No match found -- continue searching */
             if (bestEntry == NULL) {
                 ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
    -                                             (U32)(lastHashed - base));
    +                                             (U32)(lastHashed - base),
    +                                             ldmParams);
                 ip++;
                 continue;
             }
    @@ -3632,14 +3690,16 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
     
             /* Insert the current entry into the hash table */
             ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
    -                                         (U32)(lastHashed - base));
    +                                         (U32)(lastHashed - base),
    +                                         ldmParams);
     
             /* Fill the hash table from lastHashed+1 to ip+mLength */
             assert(ip + backwardMatchLength == lastHashed);
             if (ip + mLength < ilimit) {
                 rollingHash = ZSTD_ldm_fillLdmHashTable(
                                   ldmState, rollingHash, lastHashed,
    -                              ip + mLength, base, hBits);
    +                              ip + mLength, base, hBits,
    +                              ldmParams);
                 lastHashed = ip + mLength - 1;
             }
             ip += mLength;
    @@ -3670,7 +3730,8 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
                     if (ip + repLength2 < ilimit) {
                         rollingHash = ZSTD_ldm_fillLdmHashTable(
                                           ldmState, rollingHash, lastHashed,
    -                                      ip + repLength2, base, hBits);
    +                                      ip + repLength2, base, hBits,
    +                                      ldmParams);
                         lastHashed = ip + repLength2 - 1;
                     }
                     ip += repLength2;
    @@ -3721,7 +3782,7 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCa
         size_t lastLLSize;
         const BYTE* anchor;
         const ZSTD_blockCompressor blockCompressor =
    -        zc->appliedParams.enableLdm?
    +        zc->appliedParams.ldmParams.enableLdm ?
                 (zc->lowLimit < zc->dictLimit ? ZSTD_compressBlock_ldm_extDict :
                                                 ZSTD_compressBlock_ldm) :
                 ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy,
    diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c
    index f6266ade7..ac451c35e 100644
    --- a/lib/compress/zstdmt_compress.c
    +++ b/lib/compress/zstdmt_compress.c
    @@ -197,7 +197,7 @@ static ZSTD_CCtx_params ZSTDMT_makeJobCCtxParams(ZSTD_CCtx_params const params)
         jobParams.fParams = params.fParams;
         jobParams.compressionLevel = params.compressionLevel;
     
    -    jobParams.enableLdm = params.enableLdm;
    +    jobParams.ldmParams = params.ldmParams;
         return jobParams;
     }
     
    diff --git a/lib/zstd.h b/lib/zstd.h
    index c49710402..bed583c92 100644
    --- a/lib/zstd.h
    +++ b/lib/zstd.h
    @@ -390,6 +390,8 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void);   /*!< recommended size for output
     #define ZSTD_SEARCHLENGTH_MIN   3   /* only for ZSTD_btopt, other strategies are limited to 4 */
     #define ZSTD_TARGETLENGTH_MIN   4
     #define ZSTD_TARGETLENGTH_MAX 999
    +#define ZSTD_LDM_SEARCHLENGTH_MIN 4
    +#define ZSTD_LDM_SEARCHLENGTH_MAX 4096
     
     #define ZSTD_FRAMEHEADERSIZE_MAX 18    /* for static allocation */
     #define ZSTD_FRAMEHEADERSIZE_MIN  6
    @@ -980,7 +982,14 @@ typedef enum {
                                        * increases the memory usage as well as the
                                        * window size. Note: this should be set after
                                        * ZSTD_p_compressionLevel and before
    -                                   * ZSTD_p_windowLog. */
    +                                   * ZSTD_p_windowLog and other LDM parameters. */
    +    ZSTD_p_ldmHashLog,   /* Size of the table for long distance matching.
    +                           * Must be clamped between ZSTD_HASHLOG_MIN and
    +                           * ZSTD_HASHLOG_MAX */
    +    ZSTD_p_ldmMinMatch,  /* Minimum size of searched matches for long distance matcher.
    +                           * Must be clamped between ZSTD_LDM_SEARCHLENGTH_MIN
    +                           * and ZSTD_LDM_SEARCHLENGTH_MAX. */
    +
     } ZSTD_cParameter;
     
     
    diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c
    index f248d2609..dedb7eb39 100644
    --- a/tests/zstreamtest.c
    +++ b/tests/zstreamtest.c
    @@ -1381,6 +1381,8 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
                     if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_targetLength, cParams.targetLength, useOpaqueAPI) );
     
                     if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_longDistanceMatching, FUZ_rand(&lseed) & 63, useOpaqueAPI) );
    +                if (FUZ_rand(&lseed) & 7) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmMinMatch, FUZ_rand(&lseed) % 128 + 4, useOpaqueAPI ) );
    +                if (FUZ_rand(&lseed) & 7) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashLog, FUZ_rand(&lseed) % 18 + 10,  useOpaqueAPI ) );
     
                     /* unconditionally set, to be sync with decoder */
                     /* mess with frame parameters */
    
    From a1f04d518d34decb2ec5c6471d406fb8dad249ae Mon Sep 17 00:00:00 2001
    From: Stella Lau 
    Date: Fri, 1 Sep 2017 14:52:51 -0700
    Subject: [PATCH 096/248] Move hashEveryLog to cctxParams and update cli
    
    ---
     lib/common/zstd_internal.h   |  2 +-
     lib/compress/zstd_compress.c | 47 ++++++++++++++++++++++++------------
     lib/zstd.h                   | 13 +++++++---
     programs/bench.c             | 22 +++++++++++++++++
     programs/bench.h             |  3 +++
     programs/fileio.c            | 19 +++++++++++++++
     programs/fileio.h            |  3 +++
     programs/zstdcli.c           | 16 ++++++++++++
     tests/fuzzer.c               |  1 -
     tests/zstreamtest.c          |  2 --
     10 files changed, 105 insertions(+), 23 deletions(-)
    
    diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h
    index b3d9a6c6e..cd4146462 100644
    --- a/lib/common/zstd_internal.h
    +++ b/lib/common/zstd_internal.h
    @@ -256,7 +256,6 @@ typedef struct {
     typedef struct {
         ldmEntry_t* hashTable;
         BYTE* bucketOffsets;    /* Next position in bucket to insert entry */
    -    U32 hashEveryLog;       /* Log number of entries to skip */
         U64 hashPower;          /* Used to compute the rolling hash.
                                  * Depends on ldmParams.minMatchLength */
     } ldmState_t;
    @@ -266,6 +265,7 @@ typedef struct {
         U32 hashLog;            /* Log size of hashTable */
         U32 bucketLog;          /* Log number of buckets, at most 4 */
         U32 minMatchLength;     /* Minimum match length */
    +    U32 hashEveryLog;       /* Log number of entries to skip */
     } ldmParams_t;
     
     typedef struct {
    diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
    index e74787f37..fc8e9b0f3 100644
    --- a/lib/compress/zstd_compress.c
    +++ b/lib/compress/zstd_compress.c
    @@ -42,6 +42,7 @@ typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZS
     #define LDM_WINDOW_LOG 27
     #define LDM_HASH_LOG 20
     #define LDM_HASH_CHAR_OFFSET 10
    +#define LDM_HASHEVERYLOG_NOTSET 9999
     
     
     /*-*************************************
    @@ -320,6 +321,7 @@ static size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm)
         params->hashLog = LDM_HASH_LOG;
         params->bucketLog = LDM_BUCKET_SIZE_LOG;
         params->minMatchLength = LDM_MIN_MATCH_LENGTH;
    +    params->hashEveryLog = LDM_HASHEVERYLOG_NOTSET;
         return 0;
     }
     
    @@ -385,6 +387,10 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
             if (cctx->cdict) return ERROR(stage_wrong);
             return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
     
    +    case ZSTD_p_ldmHashEveryLog:
    +        if (cctx->cdict) return ERROR(stage_wrong);
    +        return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
    +
         default: return ERROR(parameter_unsupported);
         }
     }
    @@ -503,6 +509,13 @@ size_t ZSTD_CCtxParam_setParameter(
             params->ldmParams.minMatchLength = value;
             return 0;
     
    +    case ZSTD_p_ldmHashEveryLog :
    +        if (value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN) {
    +            return ERROR(parameter_outOfBound);
    +        }
    +        params->ldmParams.hashEveryLog = value;
    +        return 0;
    +
         default: return ERROR(parameter_unsupported);
         }
     }
    @@ -538,7 +551,7 @@ size_t ZSTD_CCtx_setParametersUsingCCtxParams(
                         cctx, ZSTD_p_overlapSizeLog, params->overlapSizeLog) );
         }
     
    -    /* Copy long distance matching parameter */
    +    /* Copy long distance matching parameters */
         cctx->requestedParams.ldmParams = params->ldmParams;
     
         /* customMem is used only for create/free params and can be ignored */
    @@ -742,7 +755,6 @@ size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* pa
                     + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
             size_t const optSpace = ((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btultra)) ? optBudget : 0;
     
    -        /* Ldm parameters can not currently be changed */
             size_t const ldmSpace = params->ldmParams.enableLdm ?
                 ZSTD_ldm_getTableSize(params->ldmParams.hashLog,
                                       params->ldmParams.bucketLog) : 0;
    @@ -813,7 +825,8 @@ static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1,
                (ldmParams1.enableLdm == ldmParams2.enableLdm &&
                 ldmParams1.hashLog == ldmParams2.hashLog &&
                 ldmParams1.bucketLog == ldmParams2.bucketLog &&
    -            ldmParams1.minMatchLength == ldmParams2.minMatchLength);
    +            ldmParams1.minMatchLength == ldmParams2.minMatchLength &&
    +            ldmParams1.hashEveryLog == ldmParams2.hashEveryLog);
     }
     
     /** Equivalence for resetCCtx purposes */
    @@ -866,6 +879,8 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
         if (crp == ZSTDcrp_continue) {
             if (ZSTD_equivalentParams(params, zc->appliedParams)) {
                 DEBUGLOG(5, "ZSTD_equivalentParams()==1");
    +            assert(!(params.ldmParams.enableLdm &&
    +                     params.ldmParams.hashEveryLog == LDM_HASHEVERYLOG_NOTSET));
                 zc->entropy->hufCTable_repeatMode = HUF_repeat_none;
                 zc->entropy->offcode_repeatMode = FSE_repeat_none;
                 zc->entropy->matchlength_repeatMode = FSE_repeat_none;
    @@ -874,9 +889,11 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
         }   }
     
         if (params.ldmParams.enableLdm) {
    -        zc->ldmState.hashEveryLog =
    -            params.cParams.windowLog < params.ldmParams.hashLog ?
    -                0 : params.cParams.windowLog - params.ldmParams.hashLog;
    +        if (params.ldmParams.hashEveryLog == LDM_HASHEVERYLOG_NOTSET) {
    +            params.ldmParams.hashEveryLog =
    +                    params.cParams.windowLog < params.ldmParams.hashLog ?
    +                    0 : params.cParams.windowLog - params.ldmParams.hashLog;
    +        }
             zc->ldmState.hashPower =
                     ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength);
         }
    @@ -3159,19 +3176,19 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
      *
      *  Gets the small hash, checksum, and tag from the rollingHash.
      *
    - *  If the tag matches (1 << ldmState->hashEveryLog)-1, then
    + *  If the tag matches (1 << ldmParams.hashEveryLog)-1, then
      *  creates an ldmEntry from the offset, and inserts it into the hash table.
      *
      *  hBits is the length of the small hash, which is the most significant hBits
      *  of rollingHash. The checksum is the next 32 most significant bits, followed
    - *  by ldmState->hashEveryLog bits that make up the tag. */
    + *  by ldmParams.hashEveryLog bits that make up the tag. */
     static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
                                                  U64 rollingHash, U32 hBits,
                                                  U32 const offset,
                                                  ldmParams_t const ldmParams)
     {
    -    U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmState->hashEveryLog);
    -    U32 const tagMask = (1 << ldmState->hashEveryLog) - 1;
    +    U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog);
    +    U32 const tagMask = (1 << ldmParams.hashEveryLog) - 1;
         if (tag == tagMask) {
             U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits);
             U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
    @@ -3349,7 +3366,7 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
         const U64 hashPower = ldmState->hashPower;
         const U32 hBits = ldmParams.hashLog - ldmParams.bucketLog;
         const U32 ldmBucketSize = (1 << ldmParams.bucketLog);
    -    const U32 ldmTagMask = (1 << ldmState->hashEveryLog) - 1;
    +    const U32 ldmTagMask = (1 << ldmParams.hashEveryLog) - 1;
         seqStore_t* const seqStorePtr = &(cctx->seqStore);
         const BYTE* const base = cctx->base;
         const BYTE* const istart = (const BYTE*)src;
    @@ -3388,7 +3405,7 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
             lastHashed = ip;
     
             /* Do not insert and do not look for a match */
    -        if (ZSTD_ldm_getTag(rollingHash, hBits, ldmState->hashEveryLog) !=
    +        if (ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog) !=
                     ldmTagMask) {
                ip++;
                continue;
    @@ -3546,12 +3563,12 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
                                      ZSTD_CCtx* ctx,
                                      const void* src, size_t srcSize)
     {
    -    ldmState_t* ldmState = &(ctx->ldmState);
    +    ldmState_t* const ldmState = &(ctx->ldmState);
         const ldmParams_t ldmParams = ctx->appliedParams.ldmParams;
         const U64 hashPower = ldmState->hashPower;
         const U32 hBits = ldmParams.hashLog - ldmParams.bucketLog;
         const U32 ldmBucketSize = (1 << ldmParams.bucketLog);
    -    const U32 ldmTagMask = (1 << ctx->ldmState.hashEveryLog) - 1;
    +    const U32 ldmTagMask = (1 << ldmParams.hashEveryLog) - 1;
         seqStore_t* const seqStorePtr = &(ctx->seqStore);
         const BYTE* const base = ctx->base;
         const BYTE* const dictBase = ctx->dictBase;
    @@ -3594,7 +3611,7 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
             }
             lastHashed = ip;
     
    -        if (ZSTD_ldm_getTag(rollingHash, hBits, ldmState->hashEveryLog) !=
    +        if (ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog) !=
                     ldmTagMask) {
                 /* Don't insert and don't look for a match */
                ip++;
    diff --git a/lib/zstd.h b/lib/zstd.h
    index bed583c92..a7ad9771b 100644
    --- a/lib/zstd.h
    +++ b/lib/zstd.h
    @@ -984,11 +984,16 @@ typedef enum {
                                        * ZSTD_p_compressionLevel and before
                                        * ZSTD_p_windowLog and other LDM parameters. */
         ZSTD_p_ldmHashLog,   /* Size of the table for long distance matching.
    -                           * Must be clamped between ZSTD_HASHLOG_MIN and
    -                           * ZSTD_HASHLOG_MAX */
    +                          * Must be clamped between ZSTD_HASHLOG_MIN and
    +                          * ZSTD_HASHLOG_MAX */
         ZSTD_p_ldmMinMatch,  /* Minimum size of searched matches for long distance matcher.
    -                           * Must be clamped between ZSTD_LDM_SEARCHLENGTH_MIN
    -                           * and ZSTD_LDM_SEARCHLENGTH_MAX. */
    +                          * Must be clamped between ZSTD_LDM_SEARCHLENGTH_MIN
    +                          * and ZSTD_LDM_SEARCHLENGTH_MAX. */
    +    ZSTD_p_ldmHashEveryLog,  /* Frequency of inserting/looking up entries in the
    +                              * LDM hash table. The default is
    +                              * (windowLog - ldmHashLog) to optimize hash table
    +                              * usage. Must be clamped between 0 and
    +                              * ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN. */
     
     } ZSTD_cParameter;
     
    diff --git a/programs/bench.c b/programs/bench.c
    index d77f9a20d..2a2510a2c 100644
    --- a/programs/bench.c
    +++ b/programs/bench.c
    @@ -134,6 +134,23 @@ void BMK_setLdmFlag(unsigned ldmFlag) {
         g_ldmFlag = ldmFlag;
     }
     
    +static U32 g_ldmMinMatch = 0;
    +void BMK_setLdmMinMatch(unsigned ldmMinMatch) {
    +    g_ldmMinMatch = ldmMinMatch;
    +}
    +
    +static U32 g_ldmHashLog = 0;
    +void BMK_setLdmHashLog(unsigned ldmHashLog) {
    +    g_ldmHashLog = ldmHashLog;
    +}
    +
    +#define BMK_LDM_HASHEVERYLOG_NOTSET 9999
    +static U32 g_ldmHashEveryLog = BMK_LDM_HASHEVERYLOG_NOTSET;
    +void BMK_setLdmHashEveryLog(unsigned ldmHashEveryLog) {
    +    g_ldmHashEveryLog = ldmHashEveryLog;
    +}
    +
    +
     /* ********************************************************
     *  Bench functions
     **********************************************************/
    @@ -270,6 +287,11 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_nbThreads, g_nbThreads);
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionLevel, cLevel);
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_longDistanceMatching, g_ldmFlag);
    +                    ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmMinMatch, g_ldmMinMatch);
    +                    ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmHashLog, g_ldmHashLog);
    +                    if (g_ldmHashEveryLog != BMK_LDM_HASHEVERYLOG_NOTSET) {
    +                      ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmHashEveryLog, g_ldmHashEveryLog);
    +                    }
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_windowLog, comprParams->windowLog);
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_chainLog, comprParams->chainLog);
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_searchLog, comprParams->searchLog);
    diff --git a/programs/bench.h b/programs/bench.h
    index 7fb73c4d8..04d220a92 100644
    --- a/programs/bench.h
    +++ b/programs/bench.h
    @@ -26,5 +26,8 @@ void BMK_setNotificationLevel(unsigned level);
     void BMK_setAdditionalParam(int additionalParam);
     void BMK_setDecodeOnlyMode(unsigned decodeFlag);
     void BMK_setLdmFlag(unsigned ldmFlag);
    +void BMK_setLdmMinMatch(unsigned ldmMinMatch);
    +void BMK_setLdmHashLog(unsigned ldmHashLog);
    +void BMK_setLdmHashEveryLog(unsigned ldmHashEveryLog);
     
     #endif   /* BENCH_H_121279284357 */
    diff --git a/programs/fileio.c b/programs/fileio.c
    index c86b25339..fc390afed 100644
    --- a/programs/fileio.c
    +++ b/programs/fileio.c
    @@ -217,6 +217,20 @@ static U32 g_ldmFlag = 0;
     void FIO_setLdmFlag(unsigned ldmFlag) {
         g_ldmFlag = (ldmFlag>0);
     }
    +static U32 g_ldmHashLog = 0;
    +void FIO_setLdmHashLog(unsigned ldmHashLog) {
    +    g_ldmHashLog = ldmHashLog;
    +}
    +static U32 g_ldmMinMatch = 0;
    +void FIO_setLdmMinMatch(unsigned ldmMinMatch) {
    +    g_ldmMinMatch = ldmMinMatch;
    +}
    +#define FIO_LDM_HASHEVERYLOG_NOTSET 9999
    +static U32 g_ldmHashEveryLog = FIO_LDM_HASHEVERYLOG_NOTSET;
    +void FIO_setLdmHashEveryLog(unsigned ldmHashEveryLog) {
    +    g_ldmHashEveryLog = ldmHashEveryLog;
    +}
    +
     
     
     /*-*************************************
    @@ -406,6 +420,11 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionLevel, cLevel) );
                 /* long distance matching */
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_longDistanceMatching, g_ldmFlag) );
    +            CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmHashLog, g_ldmHashLog) );
    +            CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmMinMatch, g_ldmMinMatch) );
    +            if (g_ldmHashEveryLog != FIO_LDM_HASHEVERYLOG_NOTSET) {
    +                CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmHashEveryLog, g_ldmHashEveryLog) );
    +            }
                 /* compression parameters */
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_windowLog, comprParams->windowLog) );
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_chainLog, comprParams->chainLog) );
    diff --git a/programs/fileio.h b/programs/fileio.h
    index 7e200b06e..fabb46db9 100644
    --- a/programs/fileio.h
    +++ b/programs/fileio.h
    @@ -57,6 +57,9 @@ void FIO_setNbThreads(unsigned nbThreads);
     void FIO_setBlockSize(unsigned blockSize);
     void FIO_setOverlapLog(unsigned overlapLog);
     void FIO_setLdmFlag(unsigned ldmFlag);
    +void FIO_setLdmHashLog(unsigned ldmHashLog);
    +void FIO_setLdmMinMatch(unsigned ldmMinMatch);
    +void FIO_setLdmHashEveryLog(unsigned ldmHashEveryLog);
     
     
     /*-*************************************
    diff --git a/programs/zstdcli.c b/programs/zstdcli.c
    index b5fd1be5a..78d6b339e 100644
    --- a/programs/zstdcli.c
    +++ b/programs/zstdcli.c
    @@ -72,7 +72,11 @@ static const unsigned g_defaultMaxDictSize = 110 KB;
     static const int      g_defaultDictCLevel = 3;
     static const unsigned g_defaultSelectivityLevel = 9;
     #define OVERLAP_LOG_DEFAULT 9999
    +#define LDM_HASHEVERYLOG_DEFAULT 9999
     static U32 g_overlapLog = OVERLAP_LOG_DEFAULT;
    +static U32 g_ldmHashLog = 0;
    +static U32 g_ldmMinMatch = 0;
    +static U32 g_ldmHashEveryLog = LDM_HASHEVERYLOG_DEFAULT;
     
     
     /*-************************************
    @@ -305,6 +309,9 @@ static unsigned parseCompressionParameters(const char* stringPtr, ZSTD_compressi
             if (longCommandWArg(&stringPtr, "targetLength=") || longCommandWArg(&stringPtr, "tlen=")) { params->targetLength = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
             if (longCommandWArg(&stringPtr, "strategy=") || longCommandWArg(&stringPtr, "strat=")) { params->strategy = (ZSTD_strategy)(readU32FromChar(&stringPtr)); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
             if (longCommandWArg(&stringPtr, "overlapLog=") || longCommandWArg(&stringPtr, "ovlog=")) { g_overlapLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
    +        if (longCommandWArg(&stringPtr, "ldmHashLog=") || longCommandWArg(&stringPtr, "ldmHlog=")) { g_ldmHashLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
    +        if (longCommandWArg(&stringPtr, "ldmSearchLength=") || longCommandWArg(&stringPtr, "ldmSlen=")) { g_ldmMinMatch = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
    +        if (longCommandWArg(&stringPtr, "ldmHashEveryLog=")) { g_ldmHashEveryLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
             return 0;
         }
     
    @@ -724,6 +731,9 @@ int main(int argCount, const char* argv[])
             BMK_setNbThreads(nbThreads);
             BMK_setNbSeconds(bench_nbSeconds);
             BMK_setLdmFlag(ldmFlag);
    +        BMK_setLdmMinMatch(g_ldmMinMatch);
    +        BMK_setLdmHashLog(g_ldmHashLog);
    +        BMK_setLdmHashEveryLog(g_ldmHashEveryLog);
             BMK_benchFiles(filenameTable, filenameIdx, dictFileName, cLevel, cLevelLast, &compressionParams, setRealTimePrio);
     #endif
             (void)bench_nbSeconds; (void)blockSize; (void)setRealTimePrio;
    @@ -792,6 +802,12 @@ int main(int argCount, const char* argv[])
             FIO_setNbThreads(nbThreads);
             FIO_setBlockSize((U32)blockSize);
             FIO_setLdmFlag(ldmFlag);
    +        FIO_setLdmHashLog(g_ldmHashLog);
    +        FIO_setLdmMinMatch(g_ldmMinMatch);
    +        if (g_ldmHashEveryLog != LDM_HASHEVERYLOG_DEFAULT) {
    +            FIO_setLdmHashEveryLog(g_ldmHashEveryLog);
    +        }
    +
             if (g_overlapLog!=OVERLAP_LOG_DEFAULT) FIO_setOverlapLog(g_overlapLog);
             if ((filenameIdx==1) && outFileName)
               operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel, &compressionParams);
    diff --git a/tests/fuzzer.c b/tests/fuzzer.c
    index 3b3e23b38..b23498705 100644
    --- a/tests/fuzzer.c
    +++ b/tests/fuzzer.c
    @@ -1342,7 +1342,6 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
                 dictSize = FUZ_rLogLength(&lseed, dictLog);   /* needed also for decompression */
                 dict = srcBuffer + (FUZ_rand(&lseed) % (srcBufferSize - dictSize));
     
    -            CHECK_Z ( ZSTD_CCtx_setParameter(refCtx, ZSTD_p_longDistanceMatching, FUZ_rand(&lseed)&255) );
                 if (FUZ_rand(&lseed) & 0xF) {
                     CHECK_Z ( ZSTD_compressBegin_usingDict(refCtx, dict, dictSize, cLevel) );
                 } else {
    diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c
    index dedb7eb39..f248d2609 100644
    --- a/tests/zstreamtest.c
    +++ b/tests/zstreamtest.c
    @@ -1381,8 +1381,6 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
                     if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_targetLength, cParams.targetLength, useOpaqueAPI) );
     
                     if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_longDistanceMatching, FUZ_rand(&lseed) & 63, useOpaqueAPI) );
    -                if (FUZ_rand(&lseed) & 7) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmMinMatch, FUZ_rand(&lseed) % 128 + 4, useOpaqueAPI ) );
    -                if (FUZ_rand(&lseed) & 7) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashLog, FUZ_rand(&lseed) % 18 + 10,  useOpaqueAPI ) );
     
                     /* unconditionally set, to be sync with decoder */
                     /* mess with frame parameters */
    
    From 67d4a6161cc1237cf958d3abb4d8ce1a6623119c Mon Sep 17 00:00:00 2001
    From: Stella Lau 
    Date: Sat, 2 Sep 2017 21:10:36 -0700
    Subject: [PATCH 097/248] Add ldmBucketSizeLog param
    
    ---
     lib/common/zstd_internal.h   |  2 +-
     lib/compress/zstd_compress.c | 77 ++++++++++++++++++++++++++----------
     lib/zstd.h                   | 28 +++++++------
     programs/bench.c             | 16 ++++++--
     programs/bench.h             |  1 +
     programs/fileio.c            | 18 +++++++--
     programs/fileio.h            |  1 +
     programs/zstdcli.c           | 18 +++++++--
     tests/zstreamtest.c          |  2 +-
     9 files changed, 116 insertions(+), 47 deletions(-)
    
    diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h
    index cd4146462..2a270c3e4 100644
    --- a/lib/common/zstd_internal.h
    +++ b/lib/common/zstd_internal.h
    @@ -263,7 +263,7 @@ typedef struct {
     typedef struct {
         U32 enableLdm;          /* 1 if enable long distance matching */
         U32 hashLog;            /* Log size of hashTable */
    -    U32 bucketLog;          /* Log number of buckets, at most 4 */
    +    U32 bucketSizeLog;      /* Log bucket size for collision resolution, at most 8 */
         U32 minMatchLength;     /* Minimum match length */
         U32 hashEveryLog;       /* Log number of entries to skip */
     } ldmParams_t;
    diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
    index fc8e9b0f3..d4d3ae961 100644
    --- a/lib/compress/zstd_compress.c
    +++ b/lib/compress/zstd_compress.c
    @@ -37,7 +37,6 @@ static const U32 g_searchStrength = 8;   /* control skip over incompressible dat
     typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
     
     #define LDM_BUCKET_SIZE_LOG 3
    -#define LDM_BUCKET_SIZE_LOG_MAX 4
     #define LDM_MIN_MATCH_LENGTH 64
     #define LDM_WINDOW_LOG 27
     #define LDM_HASH_LOG 20
    @@ -202,6 +201,33 @@ size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
                + cctx->outBuffSize + cctx->inBuffSize
                + ZSTDMT_sizeof_CCtx(cctx->mtctx);
     }
    +#if 0
    +static void ZSTD_debugPrintCCtxParams(ZSTD_CCtx_params* params)
    +{
    +    DEBUGLOG(2, "======CCtxParams======");
    +    DEBUGLOG(2, "cParams: %u %u %u %u %u %u %u",
    +             params->cParams.windowLog,
    +             params->cParams.chainLog,
    +             params->cParams.hashLog,
    +             params->cParams.searchLog,
    +             params->cParams.searchLength,
    +             params->cParams.targetLength,
    +             params->cParams.strategy);
    +    DEBUGLOG(2, "fParams: %u %u %u",
    +             params->fParams.contentSizeFlag,
    +             params->fParams.checksumFlag,
    +             params->fParams.noDictIDFlag);
    +    DEBUGLOG(2, "cLevel, forceWindow: %u %u",
    +             params->compressionLevel,
    +             params->forceWindow);
    +    DEBUGLOG(2, "ldm: %u %u %u %u %u",
    +             params->ldmParams.enableLdm,
    +             params->ldmParams.hashLog,
    +             params->ldmParams.bucketSizeLog,
    +             params->ldmParams.minMatchLength,
    +             params->ldmParams.hashEveryLog);
    +}
    +#endif
     
     size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
     {
    @@ -316,10 +342,10 @@ size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThre
     
     static size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm)
     {
    -    assert(LDM_BUCKET_SIZE_LOG <= LDM_BUCKET_SIZE_LOG_MAX);
    +    assert(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX);
         params->enableLdm = enableLdm>0;
         params->hashLog = LDM_HASH_LOG;
    -    params->bucketLog = LDM_BUCKET_SIZE_LOG;
    +    params->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
         params->minMatchLength = LDM_MIN_MATCH_LENGTH;
         params->hashEveryLog = LDM_HASHEVERYLOG_NOTSET;
         return 0;
    @@ -374,7 +400,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
             DEBUGLOG(5, " setting overlap with nbThreads == %u", cctx->requestedParams.nbThreads);
             return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
     
    -    case ZSTD_p_longDistanceMatching:
    +    case ZSTD_p_enableLongDistanceMatching:
             if (cctx->cdict) return ERROR(stage_wrong);
             if (value != 0) {
                 ZSTD_cLevelToCParams(cctx);
    @@ -387,6 +413,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
             if (cctx->cdict) return ERROR(stage_wrong);
             return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
     
    +    case ZSTD_p_ldmBucketSizeLog:
         case ZSTD_p_ldmHashEveryLog:
             if (cctx->cdict) return ERROR(stage_wrong);
             return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
    @@ -490,7 +517,7 @@ size_t ZSTD_CCtxParam_setParameter(
             if (params->nbThreads <= 1) return ERROR(parameter_unsupported);
             return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_overlapSectionLog, value);
     
    -    case ZSTD_p_longDistanceMatching :
    +    case ZSTD_p_enableLongDistanceMatching :
             if (value != 0) {
                 ZSTD_cLevelToCCtxParams(params);
                 params->cParams.windowLog = LDM_WINDOW_LOG;
    @@ -509,6 +536,13 @@ size_t ZSTD_CCtxParam_setParameter(
             params->ldmParams.minMatchLength = value;
             return 0;
     
    +    case ZSTD_p_ldmBucketSizeLog :
    +        if (value > ZSTD_LDM_BUCKETSIZELOG_MAX) {
    +            return ERROR(parameter_outOfBound);
    +        }
    +        params->ldmParams.bucketSizeLog = value;
    +        return 0;
    +
         case ZSTD_p_ldmHashEveryLog :
             if (value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN) {
                 return ERROR(parameter_outOfBound);
    @@ -722,12 +756,11 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u
     }
     
     /* Estimate the space needed for long distance matching tables. */
    -static size_t ZSTD_ldm_getTableSize(U32 ldmHashLog, U32 bucketLog) {
    -    size_t const ldmHSize = ((size_t)1) << ldmHashLog;
    -    size_t const ldmBucketLog =
    -        MIN(bucketLog, LDM_BUCKET_SIZE_LOG_MAX);
    +static size_t ZSTD_ldm_getTableSize(U32 hashLog, U32 bucketSizeLog) {
    +    size_t const ldmHSize = ((size_t)1) << hashLog;
    +    size_t const ldmBucketSizeLog = MIN(bucketSizeLog, hashLog);
         size_t const ldmBucketSize =
    -        ((size_t)1) << (ldmHashLog - ldmBucketLog);
    +        ((size_t)1) << (hashLog - ldmBucketSizeLog);
         return ldmBucketSize + (ldmHSize * (sizeof(ldmEntry_t)));
     }
     
    @@ -757,7 +790,7 @@ size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* pa
     
             size_t const ldmSpace = params->ldmParams.enableLdm ?
                 ZSTD_ldm_getTableSize(params->ldmParams.hashLog,
    -                                  params->ldmParams.bucketLog) : 0;
    +                                  params->ldmParams.bucketSizeLog) : 0;
     
             size_t const neededSpace = entropySpace + tableSpace + tokenSpace +
                                        optSpace + ldmSpace;
    @@ -824,7 +857,7 @@ static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1,
         return (!ldmParams1.enableLdm && !ldmParams2.enableLdm) ||
                (ldmParams1.enableLdm == ldmParams2.enableLdm &&
                 ldmParams1.hashLog == ldmParams2.hashLog &&
    -            ldmParams1.bucketLog == ldmParams2.bucketLog &&
    +            ldmParams1.bucketSizeLog == ldmParams2.bucketSizeLog &&
                 ldmParams1.minMatchLength == ldmParams2.minMatchLength &&
                 ldmParams1.hashEveryLog == ldmParams2.hashEveryLog);
     }
    @@ -889,11 +922,14 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
         }   }
     
         if (params.ldmParams.enableLdm) {
    +        /* Adjust long distance matching parameters */
             if (params.ldmParams.hashEveryLog == LDM_HASHEVERYLOG_NOTSET) {
                 params.ldmParams.hashEveryLog =
                         params.cParams.windowLog < params.ldmParams.hashLog ?
                         0 : params.cParams.windowLog - params.ldmParams.hashLog;
             }
    +        params.ldmParams.bucketSizeLog =
    +            MIN(params.ldmParams.bucketSizeLog, params.ldmParams.hashLog);
             zc->ldmState.hashPower =
                     ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength);
         }
    @@ -915,7 +951,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
     
             size_t const ldmSpace = params.ldmParams.enableLdm ?
                     ZSTD_ldm_getTableSize(params.ldmParams.hashLog,
    -                                      params.ldmParams.bucketLog) : 0;
    +                                      params.ldmParams.bucketSizeLog) : 0;
     
             /* Check if workSpace is large enough, alloc a new one if needed */
             {   size_t const entropySpace = sizeof(ZSTD_entropyCTables_t);
    @@ -997,7 +1033,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
             if (params.ldmParams.enableLdm) {
                 size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
                 size_t const ldmBucketSize =
    -                    ((size_t)1) << (params.ldmParams.hashLog - params.ldmParams.bucketLog);
    +                    ((size_t)1) << (params.ldmParams.hashLog - params.ldmParams.bucketSizeLog);
                 memset(ptr, 0, ldmSpace);
                 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
                 zc->ldmState.hashTable = (ldmEntry_t*)ptr;
    @@ -3157,7 +3193,7 @@ static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits)
     static ldmEntry_t* ZSTD_ldm_getBucket(
             ldmState_t* ldmState, size_t hash, ldmParams_t const ldmParams)
     {
    -    return ldmState->hashTable + (hash << ldmParams.bucketLog);
    +    return ldmState->hashTable + (hash << ldmParams.bucketSizeLog);
     }
     
     /** ZSTD_ldm_insertEntry() :
    @@ -3169,7 +3205,7 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
         BYTE* const bucketOffsets = ldmState->bucketOffsets;
         *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry;
         bucketOffsets[hash]++;
    -    bucketOffsets[hash] &= (1 << ldmParams.bucketLog) - 1;
    +    bucketOffsets[hash] &= (1 << ldmParams.bucketSizeLog) - 1;
     }
     
     /** ZSTD_ldm_makeEntryAndInsertByTag() :
    @@ -3364,8 +3400,8 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
         ldmState_t* const ldmState = &(cctx->ldmState);
         const ldmParams_t ldmParams = cctx->appliedParams.ldmParams;
         const U64 hashPower = ldmState->hashPower;
    -    const U32 hBits = ldmParams.hashLog - ldmParams.bucketLog;
    -    const U32 ldmBucketSize = (1 << ldmParams.bucketLog);
    +    const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog;
    +    const U32 ldmBucketSize = (1 << ldmParams.bucketSizeLog);
         const U32 ldmTagMask = (1 << ldmParams.hashEveryLog) - 1;
         seqStore_t* const seqStorePtr = &(cctx->seqStore);
         const BYTE* const base = cctx->base;
    @@ -3566,8 +3602,8 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
         ldmState_t* const ldmState = &(ctx->ldmState);
         const ldmParams_t ldmParams = ctx->appliedParams.ldmParams;
         const U64 hashPower = ldmState->hashPower;
    -    const U32 hBits = ldmParams.hashLog - ldmParams.bucketLog;
    -    const U32 ldmBucketSize = (1 << ldmParams.bucketLog);
    +    const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog;
    +    const U32 ldmBucketSize = (1 << ldmParams.bucketSizeLog);
         const U32 ldmTagMask = (1 << ldmParams.hashEveryLog) - 1;
         seqStore_t* const seqStorePtr = &(ctx->seqStore);
         const BYTE* const base = ctx->base;
    @@ -5009,7 +5045,6 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
             return flushMin;
         }
     #endif
    -
         CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) );
         DEBUGLOG(5, "completed ZSTD_compress_generic");
         return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
    diff --git a/lib/zstd.h b/lib/zstd.h
    index a7ad9771b..e7d4fbdf4 100644
    --- a/lib/zstd.h
    +++ b/lib/zstd.h
    @@ -392,6 +392,7 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void);   /*!< recommended size for output
     #define ZSTD_TARGETLENGTH_MAX 999
     #define ZSTD_LDM_SEARCHLENGTH_MIN 4
     #define ZSTD_LDM_SEARCHLENGTH_MAX 4096
    +#define ZSTD_LDM_BUCKETSIZELOG_MAX 8
     
     #define ZSTD_FRAMEHEADERSIZE_MAX 18    /* for static allocation */
     #define ZSTD_FRAMEHEADERSIZE_MIN  6
    @@ -978,22 +979,25 @@ typedef enum {
         /* advanced parameters - may not remain available after API update */
         ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize,
                                   * even when referencing into Dictionary content (default:0) */
    -    ZSTD_p_longDistanceMatching,  /* Enable long distance matching. This
    -                                   * increases the memory usage as well as the
    -                                   * window size. Note: this should be set after
    -                                   * ZSTD_p_compressionLevel and before
    -                                   * ZSTD_p_windowLog and other LDM parameters. */
    +    ZSTD_p_enableLongDistanceMatching,  /* Enable long distance matching. This increases the memory
    +                                         * usage as well as window size. Note: setting this
    +                                         * parameter resets all the LDM parameters as well as
    +                                         * ZSTD_p_windowLog. It should be set after
    +                                         * ZSTD_p_compressionLevel and before ZSTD_p_windowLog and
    +                                         * other LDM parameters. Setting the compression level
    +                                         * after this parameter overrides the window log, though LDM
    +                                         * will remain enabled until explicitly disabled. */
         ZSTD_p_ldmHashLog,   /* Size of the table for long distance matching.
    -                          * Must be clamped between ZSTD_HASHLOG_MIN and
    -                          * ZSTD_HASHLOG_MAX */
    +                          * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX. */
         ZSTD_p_ldmMinMatch,  /* Minimum size of searched matches for long distance matcher.
                               * Must be clamped between ZSTD_LDM_SEARCHLENGTH_MIN
                               * and ZSTD_LDM_SEARCHLENGTH_MAX. */
    -    ZSTD_p_ldmHashEveryLog,  /* Frequency of inserting/looking up entries in the
    -                              * LDM hash table. The default is
    -                              * (windowLog - ldmHashLog) to optimize hash table
    -                              * usage. Must be clamped between 0 and
    -                              * ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN. */
    +    ZSTD_p_ldmBucketSizeLog,  /* Log size of each bucket in the hash table for collision resolution.
    +                               * The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX. */
    +    ZSTD_p_ldmHashEveryLog,  /* Frequency of inserting/looking up entries in the LDM hash table.
    +                              * The default is MAX(0, (windowLog - ldmHashLog)) to
    +                              * optimize hash table usage.
    +                              * Must be clamped between 0 and ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN. */
     
     } ZSTD_cParameter;
     
    diff --git a/programs/bench.c b/programs/bench.c
    index 2a2510a2c..68ac8c886 100644
    --- a/programs/bench.c
    +++ b/programs/bench.c
    @@ -144,8 +144,13 @@ void BMK_setLdmHashLog(unsigned ldmHashLog) {
         g_ldmHashLog = ldmHashLog;
     }
     
    -#define BMK_LDM_HASHEVERYLOG_NOTSET 9999
    -static U32 g_ldmHashEveryLog = BMK_LDM_HASHEVERYLOG_NOTSET;
    +#define BMK_LDM_PARAM_NOTSET 9999
    +static U32 g_ldmBucketSizeLog = BMK_LDM_PARAM_NOTSET;
    +void BMK_setLdmBucketSizeLog(unsigned ldmBucketSizeLog) {
    +    g_ldmBucketSizeLog = ldmBucketSizeLog;
    +}
    +
    +static U32 g_ldmHashEveryLog = BMK_LDM_PARAM_NOTSET;
     void BMK_setLdmHashEveryLog(unsigned ldmHashEveryLog) {
         g_ldmHashEveryLog = ldmHashEveryLog;
     }
    @@ -286,10 +291,13 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
     #ifdef ZSTD_NEWAPI
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_nbThreads, g_nbThreads);
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionLevel, cLevel);
    -                    ZSTD_CCtx_setParameter(ctx, ZSTD_p_longDistanceMatching, g_ldmFlag);
    +                    ZSTD_CCtx_setParameter(ctx, ZSTD_p_enableLongDistanceMatching, g_ldmFlag);
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmMinMatch, g_ldmMinMatch);
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmHashLog, g_ldmHashLog);
    -                    if (g_ldmHashEveryLog != BMK_LDM_HASHEVERYLOG_NOTSET) {
    +                    if (g_ldmBucketSizeLog != BMK_LDM_PARAM_NOTSET) {
    +                      ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmBucketSizeLog, g_ldmBucketSizeLog);
    +                    }
    +                    if (g_ldmHashEveryLog != BMK_LDM_PARAM_NOTSET) {
                           ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmHashEveryLog, g_ldmHashEveryLog);
                         }
                         ZSTD_CCtx_setParameter(ctx, ZSTD_p_windowLog, comprParams->windowLog);
    diff --git a/programs/bench.h b/programs/bench.h
    index 04d220a92..6fd6c405e 100644
    --- a/programs/bench.h
    +++ b/programs/bench.h
    @@ -28,6 +28,7 @@ void BMK_setDecodeOnlyMode(unsigned decodeFlag);
     void BMK_setLdmFlag(unsigned ldmFlag);
     void BMK_setLdmMinMatch(unsigned ldmMinMatch);
     void BMK_setLdmHashLog(unsigned ldmHashLog);
    +void BMK_setLdmBucketSizeLog(unsigned ldmBucketSizeLog);
     void BMK_setLdmHashEveryLog(unsigned ldmHashEveryLog);
     
     #endif   /* BENCH_H_121279284357 */
    diff --git a/programs/fileio.c b/programs/fileio.c
    index fc390afed..7322328b8 100644
    --- a/programs/fileio.c
    +++ b/programs/fileio.c
    @@ -225,8 +225,14 @@ static U32 g_ldmMinMatch = 0;
     void FIO_setLdmMinMatch(unsigned ldmMinMatch) {
         g_ldmMinMatch = ldmMinMatch;
     }
    -#define FIO_LDM_HASHEVERYLOG_NOTSET 9999
    -static U32 g_ldmHashEveryLog = FIO_LDM_HASHEVERYLOG_NOTSET;
    +
    +#define FIO_LDM_PARAM_NOTSET 9999
    +static U32 g_ldmBucketSizeLog = FIO_LDM_PARAM_NOTSET;
    +void FIO_setLdmBucketSizeLog(unsigned ldmBucketSizeLog) {
    +    g_ldmBucketSizeLog = ldmBucketSizeLog;
    +}
    +
    +static U32 g_ldmHashEveryLog = FIO_LDM_PARAM_NOTSET;
     void FIO_setLdmHashEveryLog(unsigned ldmHashEveryLog) {
         g_ldmHashEveryLog = ldmHashEveryLog;
     }
    @@ -419,10 +425,14 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
                 /* compression level */
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionLevel, cLevel) );
                 /* long distance matching */
    -            CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_longDistanceMatching, g_ldmFlag) );
    +            CHECK( ZSTD_CCtx_setParameter(
    +                          ress.cctx, ZSTD_p_enableLongDistanceMatching, g_ldmFlag) );
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmHashLog, g_ldmHashLog) );
                 CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmMinMatch, g_ldmMinMatch) );
    -            if (g_ldmHashEveryLog != FIO_LDM_HASHEVERYLOG_NOTSET) {
    +            if (g_ldmBucketSizeLog != FIO_LDM_PARAM_NOTSET) {
    +                CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmBucketSizeLog, g_ldmBucketSizeLog) );
    +            }
    +            if (g_ldmHashEveryLog != FIO_LDM_PARAM_NOTSET) {
                     CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmHashEveryLog, g_ldmHashEveryLog) );
                 }
                 /* compression parameters */
    diff --git a/programs/fileio.h b/programs/fileio.h
    index fabb46db9..20ee2ebc8 100644
    --- a/programs/fileio.h
    +++ b/programs/fileio.h
    @@ -59,6 +59,7 @@ void FIO_setOverlapLog(unsigned overlapLog);
     void FIO_setLdmFlag(unsigned ldmFlag);
     void FIO_setLdmHashLog(unsigned ldmHashLog);
     void FIO_setLdmMinMatch(unsigned ldmMinMatch);
    +void FIO_setLdmBucketSizeLog(unsigned ldmBucketSizeLog);
     void FIO_setLdmHashEveryLog(unsigned ldmHashEveryLog);
     
     
    diff --git a/programs/zstdcli.c b/programs/zstdcli.c
    index 78d6b339e..a60537a0c 100644
    --- a/programs/zstdcli.c
    +++ b/programs/zstdcli.c
    @@ -72,11 +72,12 @@ static const unsigned g_defaultMaxDictSize = 110 KB;
     static const int      g_defaultDictCLevel = 3;
     static const unsigned g_defaultSelectivityLevel = 9;
     #define OVERLAP_LOG_DEFAULT 9999
    -#define LDM_HASHEVERYLOG_DEFAULT 9999
    +#define LDM_PARAM_DEFAULT 9999  /* Default for parameters where 0 is valid */
     static U32 g_overlapLog = OVERLAP_LOG_DEFAULT;
     static U32 g_ldmHashLog = 0;
     static U32 g_ldmMinMatch = 0;
    -static U32 g_ldmHashEveryLog = LDM_HASHEVERYLOG_DEFAULT;
    +static U32 g_ldmHashEveryLog = LDM_PARAM_DEFAULT;
    +static U32 g_ldmBucketSizeLog = LDM_PARAM_DEFAULT;
     
     
     /*-************************************
    @@ -311,6 +312,7 @@ static unsigned parseCompressionParameters(const char* stringPtr, ZSTD_compressi
             if (longCommandWArg(&stringPtr, "overlapLog=") || longCommandWArg(&stringPtr, "ovlog=")) { g_overlapLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
             if (longCommandWArg(&stringPtr, "ldmHashLog=") || longCommandWArg(&stringPtr, "ldmHlog=")) { g_ldmHashLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
             if (longCommandWArg(&stringPtr, "ldmSearchLength=") || longCommandWArg(&stringPtr, "ldmSlen=")) { g_ldmMinMatch = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
    +        if (longCommandWArg(&stringPtr, "ldmBucketSizeLog=")) { g_ldmBucketSizeLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
             if (longCommandWArg(&stringPtr, "ldmHashEveryLog=")) { g_ldmHashEveryLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
             return 0;
         }
    @@ -733,7 +735,12 @@ int main(int argCount, const char* argv[])
             BMK_setLdmFlag(ldmFlag);
             BMK_setLdmMinMatch(g_ldmMinMatch);
             BMK_setLdmHashLog(g_ldmHashLog);
    -        BMK_setLdmHashEveryLog(g_ldmHashEveryLog);
    +        if (g_ldmBucketSizeLog != LDM_PARAM_DEFAULT) {
    +            BMK_setLdmBucketSizeLog(g_ldmBucketSizeLog);
    +        }
    +        if (g_ldmHashEveryLog != LDM_PARAM_DEFAULT) {
    +            BMK_setLdmHashEveryLog(g_ldmHashEveryLog);
    +        }
             BMK_benchFiles(filenameTable, filenameIdx, dictFileName, cLevel, cLevelLast, &compressionParams, setRealTimePrio);
     #endif
             (void)bench_nbSeconds; (void)blockSize; (void)setRealTimePrio;
    @@ -804,7 +811,10 @@ int main(int argCount, const char* argv[])
             FIO_setLdmFlag(ldmFlag);
             FIO_setLdmHashLog(g_ldmHashLog);
             FIO_setLdmMinMatch(g_ldmMinMatch);
    -        if (g_ldmHashEveryLog != LDM_HASHEVERYLOG_DEFAULT) {
    +        if (g_ldmBucketSizeLog != LDM_PARAM_DEFAULT) {
    +            FIO_setLdmBucketSizeLog(g_ldmBucketSizeLog);
    +        }
    +        if (g_ldmHashEveryLog != LDM_PARAM_DEFAULT) {
                 FIO_setLdmHashEveryLog(g_ldmHashEveryLog);
             }
     
    diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c
    index f248d2609..76495d453 100644
    --- a/tests/zstreamtest.c
    +++ b/tests/zstreamtest.c
    @@ -1380,7 +1380,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
                     if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_minMatch, cParams.searchLength, useOpaqueAPI) );
                     if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_targetLength, cParams.targetLength, useOpaqueAPI) );
     
    -                if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_longDistanceMatching, FUZ_rand(&lseed) & 63, useOpaqueAPI) );
    +                if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_enableLongDistanceMatching, FUZ_rand(&lseed) & 63, useOpaqueAPI) );
     
                     /* unconditionally set, to be sync with decoder */
                     /* mess with frame parameters */
    
    From 423b133568765ad25f73f5e189fb13805b9baf27 Mon Sep 17 00:00:00 2001
    From: Nick Terrell 
    Date: Tue, 5 Sep 2017 11:18:13 -0700
    Subject: [PATCH 098/248] [POOL] Allow free on NULL when multithreading is
     disabled
    
    ---
     lib/common/pool.c | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/lib/common/pool.c b/lib/common/pool.c
    index 9567d112f..d7080f034 100644
    --- a/lib/common/pool.c
    +++ b/lib/common/pool.c
    @@ -236,7 +236,7 @@ POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM
     }
     
     void POOL_free(POOL_ctx* ctx) {
    -    assert(ctx == &g_ctx);
    +    assert(!ctx || ctx == &g_ctx);
         (void)ctx;
     }
     
    
    From 643d28c7015635a89703a66425634fff796efe81 Mon Sep 17 00:00:00 2001
    From: Stella Lau 
    Date: Tue, 5 Sep 2017 11:05:57 -0700
    Subject: [PATCH 099/248] Add ldm options to 'man zstd'
    
    ---
     lib/zstd.h         | 28 +++++++++++++++-------
     programs/zstd.1    | 58 +++++++++++++++++++++++++++++++++++++++++++++-
     programs/zstd.1.md | 47 +++++++++++++++++++++++++++++++++++++
     3 files changed, 123 insertions(+), 10 deletions(-)
    
    diff --git a/lib/zstd.h b/lib/zstd.h
    index e7d4fbdf4..4879c4a63 100644
    --- a/lib/zstd.h
    +++ b/lib/zstd.h
    @@ -979,24 +979,34 @@ typedef enum {
         /* advanced parameters - may not remain available after API update */
         ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize,
                                   * even when referencing into Dictionary content (default:0) */
    -    ZSTD_p_enableLongDistanceMatching,  /* Enable long distance matching. This increases the memory
    -                                         * usage as well as window size. Note: setting this
    -                                         * parameter resets all the LDM parameters as well as
    -                                         * ZSTD_p_windowLog. It should be set after
    +    ZSTD_p_enableLongDistanceMatching,  /* Enable long distance matching.
    +                                         * This parameter is designed to improve the compression
    +                                         * ratio for large inputs with long distance matches.
    +                                         * This increases the memory usage as well as window size.
    +                                         * Note: setting this parameter sets all the LDM parameters
    +                                         * as well as ZSTD_p_windowLog. It should be set after
                                              * ZSTD_p_compressionLevel and before ZSTD_p_windowLog and
                                              * other LDM parameters. Setting the compression level
                                              * after this parameter overrides the window log, though LDM
                                              * will remain enabled until explicitly disabled. */
    -    ZSTD_p_ldmHashLog,   /* Size of the table for long distance matching.
    -                          * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX. */
    +    ZSTD_p_ldmHashLog,   /* Size of the table for long distance matching, as a power of 2.
    +                          * Larger values increase memory usage and compression ratio, but decrease
    +                          * compression speed.
    +                          * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX
    +                          * (default: 20). */
         ZSTD_p_ldmMinMatch,  /* Minimum size of searched matches for long distance matcher.
    +                          * Larger/too small values usually decrease compression ratio.
                               * Must be clamped between ZSTD_LDM_SEARCHLENGTH_MIN
    -                          * and ZSTD_LDM_SEARCHLENGTH_MAX. */
    -    ZSTD_p_ldmBucketSizeLog,  /* Log size of each bucket in the hash table for collision resolution.
    -                               * The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX. */
    +                          * and ZSTD_LDM_SEARCHLENGTH_MAX (default: 64). */
    +    ZSTD_p_ldmBucketSizeLog,  /* Log size of each bucket in the LDM hash table for collision resolution.
    +                               * Larger values usually improve collision resolution but may decrease
    +                               * compression speed.
    +                               * The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX (default: 3). */
         ZSTD_p_ldmHashEveryLog,  /* Frequency of inserting/looking up entries in the LDM hash table.
                                   * The default is MAX(0, (windowLog - ldmHashLog)) to
                                   * optimize hash table usage.
    +                              * Larger values improve compression speed. Deviating far from the
    +                              * default value will likely result in a decrease in compression ratio.
                                   * Must be clamped between 0 and ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN. */
     
     } ZSTD_cParameter;
    diff --git a/programs/zstd.1 b/programs/zstd.1
    index 5a91eea28..13c804ae5 100644
    --- a/programs/zstd.1
    +++ b/programs/zstd.1
    @@ -1,5 +1,5 @@
     .
    -.TH "ZSTD" "1" "August 2017" "zstd 1.3.1" "User Commands"
    +.TH "ZSTD" "1" "September 2017" "zstd 1.3.1" "User Commands"
     .
     .SH "NAME"
     \fBzstd\fR \- zstd, zstdmt, unzstd, zstdcat \- Compress or decompress \.zst files
    @@ -104,6 +104,10 @@ Display information related to a zstd compressed file, such as size, ratio, and
     unlocks high compression levels 20+ (maximum 22), using a lot more memory\. Note that decompression will also require more memory when using these levels\.
     .
     .TP
    +\fB\-\-long\fR
    +enables long distance matching\. This increases the window size (\fBwindowLog\fR) and memory usage for both the compressor and decompressor\. This setting is designed to improve the compression ratio for files with long matches at a large distance (up to the maximum window size, 128 MiB)\.
    +.
    +.TP
     \fB\-T#\fR, \fB\-\-threads=#\fR
     Compress using \fB#\fR threads (default: 1)\. If \fB#\fR is 0, attempt to detect and use the number of physical CPU cores\. In all cases, the nb of threads is capped to ZSTDMT_NBTHREADS_MAX==256\. This modifier does nothing if \fBzstd\fR is compiled without multithread support\.
     .
    @@ -322,6 +326,58 @@ Determine \fBoverlapSize\fR, amount of data reloaded from previous job\. This pa
     .IP
     The minimum \fIovlog\fR is 0, and the maximum is 9\. 0 means "no overlap", hence completely independent jobs\. 9 means "full overlap", meaning up to \fBwindowSize\fR is reloaded from previous job\. Reducing \fIovlog\fR by 1 reduces the amount of reload by a factor 2\. Default \fIovlog\fR is 6, which means "reload \fBwindowSize / 8\fR"\. Exception : the maximum compression level (22) has a default \fIovlog\fR of 9\.
     .
    +.TP
    +\fBldmHashLog\fR=\fIldmHlog\fR, \fBldmHlog\fR=\fIldmHlog\fR
    +Specify the maximum size for a hash table used for long distance matching\.
    +.
    +.IP
    +This option is ignored unless long distance matching is enabled\.
    +.
    +.IP
    +Bigger hash tables usually improve compression ratio at the expense of more memory during compression and a decrease in compression speed\.
    +.
    +.IP
    +The minimum \fIldmHlog\fR is 6 and the maximum is 26 (default: 20)\.
    +.
    +.TP
    +\fBldmSearchLength\fR=\fIldmSlen\fR, \fBldmSlen\fR=\fIldmSlen\fR
    +Specify the minimum searched length of a match for long distance matching\.
    +.
    +.IP
    +This option is ignored unless long distance matching is enabled\.
    +.
    +.IP
    +Larger/very small values usually decrease compression ratio\.
    +.
    +.IP
    +The minumum \fIldmSlen\fR is 4 and the maximum is 4096 (default: 64)\.
    +.
    +.TP
    +\fBldmBucketSizeLog\fR=\fIldmBucketSizeLog\fR
    +Specify the size of each bucket for the hash table used for long distance matching\.
    +.
    +.IP
    +This option is ignored unless long distance matching is enabled\.
    +.
    +.IP
    +Larger bucket sizes improve collision resolution but decrease compression speed\.
    +.
    +.IP
    +The minimum \fIldmBucketSizeLog\fR is 0 and the maximum is 8 (default: 3)\.
    +.
    +.TP
    +\fBldmHashEveryLog\fR=\fIldmHashEveryLog\fR
    +Specify the frequency of inserting entries into the long distance matching hash table\.
    +.
    +.IP
    +This option is ignored unless long distance matching is enabled\.
    +.
    +.IP
    +Larger values will improve compression speed\. Deviating far from the default value will likely result in a decrease in compression ratio\.
    +.
    +.IP
    +The default value is \fBwLog \- ldmHlog\fR\.
    +.
     .SS "\-B#:"
     Select the size of each compression job\. This parameter is available only when multi\-threading is enabled\. Default value is \fB4 * windowSize\fR, which means it varies depending on compression level\. \fB\-B#\fR makes it possible to select a custom value\. Note that job size must respect a minimum value which is enforced transparently\. This minimum is either 1 MB, or \fBoverlapSize\fR, whichever is largest\.
     .
    diff --git a/programs/zstd.1.md b/programs/zstd.1.md
    index 4310afa1a..5f6aa4500 100644
    --- a/programs/zstd.1.md
    +++ b/programs/zstd.1.md
    @@ -105,6 +105,12 @@ the last one takes effect.
     * `--ultra`:
         unlocks high compression levels 20+ (maximum 22), using a lot more memory.
         Note that decompression will also require more memory when using these levels.
    +* `--long`:
    +    enables long distance matching.
    +    This increases the window size (`windowLog`) and memory usage for both the
    +    compressor and decompressor. This setting is designed to improve the
    +    compression ratio for files with long matches at a large distance
    +    (up to the maximum window size, 128 MiB).
     * `-T#`, `--threads=#`:
         Compress using `#` threads (default: 1).
         If `#` is 0, attempt to detect and use the number of physical CPU cores.
    @@ -327,6 +333,47 @@ The list of available _options_:
         Default _ovlog_ is 6, which means "reload `windowSize / 8`".
         Exception : the maximum compression level (22) has a default _ovlog_ of 9.
     
    +- `ldmHashLog`=_ldmHlog_, `ldmHlog`=_ldmHlog_:
    +    Specify the maximum size for a hash table used for long distance matching.
    +
    +    This option is ignored unless long distance matching is enabled.
    +
    +    Bigger hash tables usually improve compression ratio at the expense of more
    +    memory during compression and a decrease in compression speed.
    +
    +    The minimum _ldmHlog_ is 6 and the maximum is 26 (default: 20).
    +
    +- `ldmSearchLength`=_ldmSlen_, `ldmSlen`=_ldmSlen_:
    +    Specify the minimum searched length of a match for long distance matching.
    +
    +    This option is ignored unless long distance matching is enabled.
    +
    +    Larger/very small values usually decrease compression ratio.
    +
    +    The minumum _ldmSlen_ is 4 and the maximum is 4096 (default: 64).
    +
    +- `ldmBucketSizeLog`=_ldmBucketSizeLog_:
    +    Specify the size of each bucket for the hash table used for long distance
    +    matching.
    +
    +    This option is ignored unless long distance matching is enabled.
    +
    +    Larger bucket sizes improve collision resolution but decrease compression
    +    speed.
    +
    +    The minimum _ldmBucketSizeLog_ is 0 and the maximum is 8 (default: 3).
    +
    +- `ldmHashEveryLog`=_ldmHashEveryLog_:
    +    Specify the frequency of inserting entries into the long distance matching
    +    hash table.
    +
    +    This option is ignored unless long distance matching is enabled.
    +
    +    Larger values will improve compression speed. Deviating far from the
    +    default value will likely result in a decrease in compression ratio.
    +
    +    The default value is `wLog - ldmHlog`.
    +
     ### -B#:
     Select the size of each compression job.
     This parameter is available only when multi-threading is enabled.
    
    From fd0071da29bad93bcd3526fed2ed9cdf9f46bced Mon Sep 17 00:00:00 2001
    From: Stella Lau 
    Date: Tue, 5 Sep 2017 15:34:17 -0700
    Subject: [PATCH 100/248] Fix parameter handling with ZSTD_copyCCtx
    
    ---
     lib/compress/zstd_compress.c | 6 +++++-
     1 file changed, 5 insertions(+), 1 deletion(-)
    
    diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
    index d048706c0..978be3c8d 100644
    --- a/lib/compress/zstd_compress.c
    +++ b/lib/compress/zstd_compress.c
    @@ -918,6 +918,8 @@ void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
     
     /*! ZSTD_copyCCtx_internal() :
      *  Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
    + *  The "context", in this case, refers to the hash and chain tables, entropy
    + *  tables, and dictionary offsets.
      *  Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
      *  pledgedSrcSize=0 means "empty" if fParams.contentSizeFlag=1
      *  @return : 0, or an error code */
    @@ -931,7 +933,9 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
         if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
     
         memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
    -    {   ZSTD_CCtx_params params = srcCCtx->appliedParams;
    +    {   ZSTD_CCtx_params params = dstCCtx->requestedParams;
    +        /* Copy only compression parameters related to tables. */
    +        params.cParams = srcCCtx->appliedParams.cParams;
             params.fParams = fParams;
             ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
                                     ZSTDcrp_noMemset, zbuff);
    
    From 08d33fe1c91cb2f6a4f8316c2df3731e904df2c4 Mon Sep 17 00:00:00 2001
    From: Stella Lau 
    Date: Tue, 5 Sep 2017 15:50:14 -0700
    Subject: [PATCH 101/248] Fix parameter handling in copyCCtx with cdict
    
    ---
     lib/compress/zstd_compress.c | 3 ++-
     1 file changed, 2 insertions(+), 1 deletion(-)
    
    diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
    index d4d3ae961..7863fae0a 100644
    --- a/lib/compress/zstd_compress.c
    +++ b/lib/compress/zstd_compress.c
    @@ -1094,7 +1094,8 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
         if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
     
         memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
    -    {   ZSTD_CCtx_params params = srcCCtx->appliedParams;
    +    {   ZSTD_CCtx_params params = dstCCtx->requestedParams;
    +        params.cParams = srcCCtx->appliedParams.cParams;
             params.fParams = fParams;
             ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
                                     ZSTDcrp_noMemset, zbuff);
    
    From 721726d688a106e2ff13747a789843c74ea3a4e1 Mon Sep 17 00:00:00 2001
    From: Nick Terrell 
    Date: Fri, 1 Sep 2017 18:28:35 -0700
    Subject: [PATCH 102/248] Split parsers out of zstd_compress.c
    
    ---
     lib/compress/zstd_compress.c    | 1609 +------------------------------
     lib/compress/zstd_compress.h    |  301 ++++++
     lib/compress/zstd_double_fast.c |  313 ++++++
     lib/compress/zstd_double_fast.h |   27 +
     lib/compress/zstd_fast.c        |  247 +++++
     lib/compress/zstd_fast.h        |   29 +
     lib/compress/zstd_lazy.c        |  752 +++++++++++++++
     lib/compress/zstd_lazy.h        |   37 +
     lib/compress/zstd_opt.c         |  954 ++++++++++++++++++
     lib/compress/zstd_opt.h         |  937 +-----------------
     10 files changed, 2679 insertions(+), 2527 deletions(-)
     create mode 100644 lib/compress/zstd_compress.h
     create mode 100644 lib/compress/zstd_double_fast.c
     create mode 100644 lib/compress/zstd_double_fast.h
     create mode 100644 lib/compress/zstd_fast.c
     create mode 100644 lib/compress/zstd_fast.h
     create mode 100644 lib/compress/zstd_lazy.c
     create mode 100644 lib/compress/zstd_lazy.h
     create mode 100644 lib/compress/zstd_opt.c
    
    diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
    index d048706c0..de5985828 100644
    --- a/lib/compress/zstd_compress.c
    +++ b/lib/compress/zstd_compress.c
    @@ -25,17 +25,13 @@
     #include "fse.h"
     #define HUF_STATIC_LINKING_ONLY
     #include "huf.h"
    -#include "zstd_internal.h"  /* includes zstd.h */
    -#include "zstdmt_compress.h"
    +#include "zstd_compress.h"
    +#include "zstd_fast.h"
    +#include "zstd_double_fast.h"
    +#include "zstd_lazy.h"
    +#include "zstd_opt.h"
     
     
    -/*-*************************************
    -*  Constants
    -***************************************/
    -static const U32 g_searchStrength = 8;   /* control skip over incompressible data */
    -#define HASH_READ_SIZE 8
    -typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
    -
     
     /*-*************************************
     *  Helper functions
    @@ -61,8 +57,6 @@ static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
     /*-*************************************
     *  Context memory management
     ***************************************/
    -typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage;
    -
     struct ZSTD_CDict_s {
         void* dictBuffer;
         const void* dictContent;
    @@ -70,64 +64,6 @@ struct ZSTD_CDict_s {
         ZSTD_CCtx* refContext;
     };  /* typedef'd to ZSTD_CDict within "zstd.h" */
     
    -typedef struct ZSTD_prefixDict_s {
    -    const void* dict;
    -    size_t dictSize;
    -    ZSTD_dictMode_e dictMode;
    -} ZSTD_prefixDict;
    -
    -struct ZSTD_CCtx_s {
    -    const BYTE* nextSrc;    /* next block here to continue on current prefix */
    -    const BYTE* base;       /* All regular indexes relative to this position */
    -    const BYTE* dictBase;   /* extDict indexes relative to this position */
    -    U32   dictLimit;        /* below that point, need extDict */
    -    U32   lowLimit;         /* below that point, no more data */
    -    U32   nextToUpdate;     /* index from which to continue dictionary update */
    -    U32   nextToUpdate3;    /* index from which to continue dictionary update */
    -    U32   hashLog3;         /* dispatch table : larger == faster, more memory */
    -    U32   loadedDictEnd;    /* index of end of dictionary */
    -    ZSTD_compressionStage_e stage;
    -    U32   dictID;
    -    ZSTD_CCtx_params requestedParams;
    -    ZSTD_CCtx_params appliedParams;
    -    void* workSpace;
    -    size_t workSpaceSize;
    -    size_t blockSize;
    -    U64 pledgedSrcSizePlusOne;  /* this way, 0 (default) == unknown */
    -    U64 consumedSrcSize;
    -    XXH64_state_t xxhState;
    -    ZSTD_customMem customMem;
    -    size_t staticSize;
    -
    -    seqStore_t seqStore;    /* sequences storage ptrs */
    -    optState_t optState;
    -    U32* hashTable;
    -    U32* hashTable3;
    -    U32* chainTable;
    -    ZSTD_entropyCTables_t* entropy;
    -
    -    /* streaming */
    -    char*  inBuff;
    -    size_t inBuffSize;
    -    size_t inToCompress;
    -    size_t inBuffPos;
    -    size_t inBuffTarget;
    -    char*  outBuff;
    -    size_t outBuffSize;
    -    size_t outBuffContentSize;
    -    size_t outBuffFlushedSize;
    -    ZSTD_cStreamStage streamStage;
    -    U32    frameEnded;
    -
    -    /* Dictionary */
    -    ZSTD_CDict* cdictLocal;
    -    const ZSTD_CDict* cdict;
    -    ZSTD_prefixDict prefixDict;   /* single-usage dictionary */
    -
    -    /* Multi-threading */
    -    ZSTDMT_CCtx* mtctx;
    -};
    -
     
     ZSTD_CCtx* ZSTD_createCCtx(void)
     {
    @@ -1141,24 +1077,6 @@ static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t * entropy,
         return lhSize+cLitSize;
     }
     
    -static const BYTE LL_Code[64] = {  0,  1,  2,  3,  4,  5,  6,  7,
    -                                   8,  9, 10, 11, 12, 13, 14, 15,
    -                                  16, 16, 17, 17, 18, 18, 19, 19,
    -                                  20, 20, 20, 20, 21, 21, 21, 21,
    -                                  22, 22, 22, 22, 22, 22, 22, 22,
    -                                  23, 23, 23, 23, 23, 23, 23, 23,
    -                                  24, 24, 24, 24, 24, 24, 24, 24,
    -                                  24, 24, 24, 24, 24, 24, 24, 24 };
    -
    -static const BYTE ML_Code[128] = { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
    -                                  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
    -                                  32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
    -                                  38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
    -                                  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
    -                                  41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
    -                                  42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
    -                                  42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
    -
     
     void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
     {
    @@ -1445,1523 +1363,6 @@ MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
     }
     
     
    -/*! ZSTD_storeSeq() :
    -    Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
    -    `offsetCode` : distance to match, or 0 == repCode.
    -    `matchCode` : matchLength - MINMATCH
    -*/
    -MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode)
    -{
    -#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6)
    -    static const BYTE* g_start = NULL;
    -    U32 const pos = (U32)((const BYTE*)literals - g_start);
    -    if (g_start==NULL) g_start = (const BYTE*)literals;
    -    if ((pos > 0) && (pos < 1000000000))
    -        DEBUGLOG(6, "Cpos %6u :%5u literals & match %3u bytes at distance %6u",
    -               pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
    -#endif
    -    /* copy Literals */
    -    assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + 128 KB);
    -    ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
    -    seqStorePtr->lit += litLength;
    -
    -    /* literal Length */
    -    if (litLength>0xFFFF) {
    -        seqStorePtr->longLengthID = 1;
    -        seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
    -    }
    -    seqStorePtr->sequences[0].litLength = (U16)litLength;
    -
    -    /* match offset */
    -    seqStorePtr->sequences[0].offset = offsetCode + 1;
    -
    -    /* match Length */
    -    if (matchCode>0xFFFF) {
    -        seqStorePtr->longLengthID = 2;
    -        seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
    -    }
    -    seqStorePtr->sequences[0].matchLength = (U16)matchCode;
    -
    -    seqStorePtr->sequences++;
    -}
    -
    -
    -/*-*************************************
    -*  Match length counter
    -***************************************/
    -static unsigned ZSTD_NbCommonBytes (register size_t val)
    -{
    -    if (MEM_isLittleEndian()) {
    -        if (MEM_64bits()) {
    -#       if defined(_MSC_VER) && defined(_WIN64)
    -            unsigned long r = 0;
    -            _BitScanForward64( &r, (U64)val );
    -            return (unsigned)(r>>3);
    -#       elif defined(__GNUC__) && (__GNUC__ >= 3)
    -            return (__builtin_ctzll((U64)val) >> 3);
    -#       else
    -            static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
    -                                                     0, 3, 1, 3, 1, 4, 2, 7,
    -                                                     0, 2, 3, 6, 1, 5, 3, 5,
    -                                                     1, 3, 4, 4, 2, 5, 6, 7,
    -                                                     7, 0, 1, 2, 3, 3, 4, 6,
    -                                                     2, 6, 5, 5, 3, 4, 5, 6,
    -                                                     7, 1, 2, 4, 6, 4, 4, 5,
    -                                                     7, 2, 6, 5, 7, 6, 7, 7 };
    -            return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
    -#       endif
    -        } else { /* 32 bits */
    -#       if defined(_MSC_VER)
    -            unsigned long r=0;
    -            _BitScanForward( &r, (U32)val );
    -            return (unsigned)(r>>3);
    -#       elif defined(__GNUC__) && (__GNUC__ >= 3)
    -            return (__builtin_ctz((U32)val) >> 3);
    -#       else
    -            static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
    -                                                     3, 2, 2, 1, 3, 2, 0, 1,
    -                                                     3, 3, 1, 2, 2, 2, 2, 0,
    -                                                     3, 1, 2, 0, 1, 0, 1, 1 };
    -            return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
    -#       endif
    -        }
    -    } else {  /* Big Endian CPU */
    -        if (MEM_64bits()) {
    -#       if defined(_MSC_VER) && defined(_WIN64)
    -            unsigned long r = 0;
    -            _BitScanReverse64( &r, val );
    -            return (unsigned)(r>>3);
    -#       elif defined(__GNUC__) && (__GNUC__ >= 3)
    -            return (__builtin_clzll(val) >> 3);
    -#       else
    -            unsigned r;
    -            const unsigned n32 = sizeof(size_t)*4;   /* calculate this way due to compiler complaining in 32-bits mode */
    -            if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
    -            if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
    -            r += (!val);
    -            return r;
    -#       endif
    -        } else { /* 32 bits */
    -#       if defined(_MSC_VER)
    -            unsigned long r = 0;
    -            _BitScanReverse( &r, (unsigned long)val );
    -            return (unsigned)(r>>3);
    -#       elif defined(__GNUC__) && (__GNUC__ >= 3)
    -            return (__builtin_clz((U32)val) >> 3);
    -#       else
    -            unsigned r;
    -            if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
    -            r += (!val);
    -            return r;
    -#       endif
    -    }   }
    -}
    -
    -
    -static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
    -{
    -    const BYTE* const pStart = pIn;
    -    const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
    -
    -    while (pIn < pInLoopLimit) {
    -        size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
    -        if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
    -        pIn += ZSTD_NbCommonBytes(diff);
    -        return (size_t)(pIn - pStart);
    -    }
    -    if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
    -    if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
    -    if ((pIn> (32-h) ; }
    -MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
    -
    -static const U32 prime4bytes = 2654435761U;
    -static U32    ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
    -static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
    -
    -static const U64 prime5bytes = 889523592379ULL;
    -static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u  << (64-40)) * prime5bytes) >> (64-h)) ; }
    -static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
    -
    -static const U64 prime6bytes = 227718039650203ULL;
    -static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u  << (64-48)) * prime6bytes) >> (64-h)) ; }
    -static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
    -
    -static const U64 prime7bytes = 58295818150454627ULL;
    -static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u  << (64-56)) * prime7bytes) >> (64-h)) ; }
    -static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
    -
    -static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
    -static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
    -static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
    -
    -static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
    -{
    -    switch(mls)
    -    {
    -    default:
    -    case 4: return ZSTD_hash4Ptr(p, hBits);
    -    case 5: return ZSTD_hash5Ptr(p, hBits);
    -    case 6: return ZSTD_hash6Ptr(p, hBits);
    -    case 7: return ZSTD_hash7Ptr(p, hBits);
    -    case 8: return ZSTD_hash8Ptr(p, hBits);
    -    }
    -}
    -
    -
    -/*-*************************************
    -*  Fast Scan
    -***************************************/
    -static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
    -{
    -    U32* const hashTable = zc->hashTable;
    -    U32  const hBits = zc->appliedParams.cParams.hashLog;
    -    const BYTE* const base = zc->base;
    -    const BYTE* ip = base + zc->nextToUpdate;
    -    const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
    -    const size_t fastHashFillStep = 3;
    -
    -    while(ip <= iend) {
    -        hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
    -        ip += fastHashFillStep;
    -    }
    -}
    -
    -
    -FORCE_INLINE_TEMPLATE
    -void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
    -                               const void* src, size_t srcSize,
    -                               const U32 mls)
    -{
    -    U32* const hashTable = cctx->hashTable;
    -    U32  const hBits = cctx->appliedParams.cParams.hashLog;
    -    seqStore_t* seqStorePtr = &(cctx->seqStore);
    -    const BYTE* const base = cctx->base;
    -    const BYTE* const istart = (const BYTE*)src;
    -    const BYTE* ip = istart;
    -    const BYTE* anchor = istart;
    -    const U32   lowestIndex = cctx->dictLimit;
    -    const BYTE* const lowest = base + lowestIndex;
    -    const BYTE* const iend = istart + srcSize;
    -    const BYTE* const ilimit = iend - HASH_READ_SIZE;
    -    U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
    -    U32 offsetSaved = 0;
    -
    -    /* init */
    -    ip += (ip==lowest);
    -    {   U32 const maxRep = (U32)(ip-lowest);
    -        if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
    -        if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
    -    }
    -
    -    /* Main Search Loop */
    -    while (ip < ilimit) {   /* < instead of <=, because repcode check at (ip+1) */
    -        size_t mLength;
    -        size_t const h = ZSTD_hashPtr(ip, hBits, mls);
    -        U32 const current = (U32)(ip-base);
    -        U32 const matchIndex = hashTable[h];
    -        const BYTE* match = base + matchIndex;
    -        hashTable[h] = current;   /* update hash table */
    -
    -        if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
    -            mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
    -            ip++;
    -            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
    -        } else {
    -            U32 offset;
    -            if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
    -                ip += ((ip-anchor) >> g_searchStrength) + 1;
    -                continue;
    -            }
    -            mLength = ZSTD_count(ip+4, match+4, iend) + 4;
    -            offset = (U32)(ip-match);
    -            while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
    -            offset_2 = offset_1;
    -            offset_1 = offset;
    -
    -            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
    -        }
    -
    -        /* match found */
    -        ip += mLength;
    -        anchor = ip;
    -
    -        if (ip <= ilimit) {
    -            /* Fill Table */
    -            hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;  /* here because current+2 could be > iend-8 */
    -            hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
    -            /* check immediate repcode */
    -            while ( (ip <= ilimit)
    -                 && ( (offset_2>0)
    -                 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
    -                /* store sequence */
    -                size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
    -                { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; }  /* swap offset_2 <=> offset_1 */
    -                hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
    -                ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
    -                ip += rLength;
    -                anchor = ip;
    -                continue;   /* faster when present ... (?) */
    -    }   }   }
    -
    -    /* save reps for next block */
    -    seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
    -    seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
    -
    -    /* Last Literals */
    -    {   size_t const lastLLSize = iend - anchor;
    -        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    -        seqStorePtr->lit += lastLLSize;
    -    }
    -}
    -
    -
    -static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
    -                       const void* src, size_t srcSize)
    -{
    -    const U32 mls = ctx->appliedParams.cParams.searchLength;
    -    switch(mls)
    -    {
    -    default: /* includes case 3 */
    -    case 4 :
    -        ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
    -    case 5 :
    -        ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
    -    case 6 :
    -        ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
    -    case 7 :
    -        ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
    -    }
    -}
    -
    -
    -static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
    -                                 const void* src, size_t srcSize,
    -                                 const U32 mls)
    -{
    -    U32* hashTable = ctx->hashTable;
    -    const U32 hBits = ctx->appliedParams.cParams.hashLog;
    -    seqStore_t* seqStorePtr = &(ctx->seqStore);
    -    const BYTE* const base = ctx->base;
    -    const BYTE* const dictBase = ctx->dictBase;
    -    const BYTE* const istart = (const BYTE*)src;
    -    const BYTE* ip = istart;
    -    const BYTE* anchor = istart;
    -    const U32   lowestIndex = ctx->lowLimit;
    -    const BYTE* const dictStart = dictBase + lowestIndex;
    -    const U32   dictLimit = ctx->dictLimit;
    -    const BYTE* const lowPrefixPtr = base + dictLimit;
    -    const BYTE* const dictEnd = dictBase + dictLimit;
    -    const BYTE* const iend = istart + srcSize;
    -    const BYTE* const ilimit = iend - 8;
    -    U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
    -
    -    /* Search Loop */
    -    while (ip < ilimit) {  /* < instead of <=, because (ip+1) */
    -        const size_t h = ZSTD_hashPtr(ip, hBits, mls);
    -        const U32 matchIndex = hashTable[h];
    -        const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
    -        const BYTE* match = matchBase + matchIndex;
    -        const U32 current = (U32)(ip-base);
    -        const U32 repIndex = current + 1 - offset_1;   /* offset_1 expected <= current +1 */
    -        const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
    -        const BYTE* repMatch = repBase + repIndex;
    -        size_t mLength;
    -        hashTable[h] = current;   /* update hash table */
    -
    -        if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
    -           && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
    -            const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
    -            mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
    -            ip++;
    -            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
    -        } else {
    -            if ( (matchIndex < lowestIndex) ||
    -                 (MEM_read32(match) != MEM_read32(ip)) ) {
    -                ip += ((ip-anchor) >> g_searchStrength) + 1;
    -                continue;
    -            }
    -            {   const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
    -                const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
    -                U32 offset;
    -                mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
    -                while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; }   /* catch up */
    -                offset = current - matchIndex;
    -                offset_2 = offset_1;
    -                offset_1 = offset;
    -                ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
    -        }   }
    -
    -        /* found a match : store it */
    -        ip += mLength;
    -        anchor = ip;
    -
    -        if (ip <= ilimit) {
    -            /* Fill Table */
    -            hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
    -            hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
    -            /* check immediate repcode */
    -            while (ip <= ilimit) {
    -                U32 const current2 = (U32)(ip-base);
    -                U32 const repIndex2 = current2 - offset_2;
    -                const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
    -                if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex))  /* intentional overflow */
    -                   && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
    -                    const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
    -                    size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
    -                    U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */
    -                    ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
    -                    hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
    -                    ip += repLength2;
    -                    anchor = ip;
    -                    continue;
    -                }
    -                break;
    -    }   }   }
    -
    -    /* save reps for next block */
    -    seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
    -
    -    /* Last Literals */
    -    {   size_t const lastLLSize = iend - anchor;
    -        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    -        seqStorePtr->lit += lastLLSize;
    -    }
    -}
    -
    -
    -static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
    -                         const void* src, size_t srcSize)
    -{
    -    U32 const mls = ctx->appliedParams.cParams.searchLength;
    -    switch(mls)
    -    {
    -    default: /* includes case 3 */
    -    case 4 :
    -        ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
    -    case 5 :
    -        ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
    -    case 6 :
    -        ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
    -    case 7 :
    -        ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
    -    }
    -}
    -
    -
    -/*-*************************************
    -*  Double Fast
    -***************************************/
    -static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
    -{
    -    U32* const hashLarge = cctx->hashTable;
    -    U32  const hBitsL = cctx->appliedParams.cParams.hashLog;
    -    U32* const hashSmall = cctx->chainTable;
    -    U32  const hBitsS = cctx->appliedParams.cParams.chainLog;
    -    const BYTE* const base = cctx->base;
    -    const BYTE* ip = base + cctx->nextToUpdate;
    -    const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
    -    const size_t fastHashFillStep = 3;
    -
    -    while(ip <= iend) {
    -        hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
    -        hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
    -        ip += fastHashFillStep;
    -    }
    -}
    -
    -
    -FORCE_INLINE_TEMPLATE
    -void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
    -                                 const void* src, size_t srcSize,
    -                                 const U32 mls)
    -{
    -    U32* const hashLong = cctx->hashTable;
    -    const U32 hBitsL = cctx->appliedParams.cParams.hashLog;
    -    U32* const hashSmall = cctx->chainTable;
    -    const U32 hBitsS = cctx->appliedParams.cParams.chainLog;
    -    seqStore_t* seqStorePtr = &(cctx->seqStore);
    -    const BYTE* const base = cctx->base;
    -    const BYTE* const istart = (const BYTE*)src;
    -    const BYTE* ip = istart;
    -    const BYTE* anchor = istart;
    -    const U32 lowestIndex = cctx->dictLimit;
    -    const BYTE* const lowest = base + lowestIndex;
    -    const BYTE* const iend = istart + srcSize;
    -    const BYTE* const ilimit = iend - HASH_READ_SIZE;
    -    U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
    -    U32 offsetSaved = 0;
    -
    -    /* init */
    -    ip += (ip==lowest);
    -    {   U32 const maxRep = (U32)(ip-lowest);
    -        if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
    -        if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
    -    }
    -
    -    /* Main Search Loop */
    -    while (ip < ilimit) {   /* < instead of <=, because repcode check at (ip+1) */
    -        size_t mLength;
    -        size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
    -        size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
    -        U32 const current = (U32)(ip-base);
    -        U32 const matchIndexL = hashLong[h2];
    -        U32 const matchIndexS = hashSmall[h];
    -        const BYTE* matchLong = base + matchIndexL;
    -        const BYTE* match = base + matchIndexS;
    -        hashLong[h2] = hashSmall[h] = current;   /* update hash tables */
    -
    -        assert(offset_1 <= current);   /* supposed guaranteed by construction */
    -        if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
    -            /* favor repcode */
    -            mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
    -            ip++;
    -            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
    -        } else {
    -            U32 offset;
    -            if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
    -                mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
    -                offset = (U32)(ip-matchLong);
    -                while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
    -            } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
    -                size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
    -                U32 const matchIndexL3 = hashLong[hl3];
    -                const BYTE* matchL3 = base + matchIndexL3;
    -                hashLong[hl3] = current + 1;
    -                if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
    -                    mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
    -                    ip++;
    -                    offset = (U32)(ip-matchL3);
    -                    while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
    -                } else {
    -                    mLength = ZSTD_count(ip+4, match+4, iend) + 4;
    -                    offset = (U32)(ip-match);
    -                    while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
    -                }
    -            } else {
    -                ip += ((ip-anchor) >> g_searchStrength) + 1;
    -                continue;
    -            }
    -
    -            offset_2 = offset_1;
    -            offset_1 = offset;
    -
    -            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
    -        }
    -
    -        /* match found */
    -        ip += mLength;
    -        anchor = ip;
    -
    -        if (ip <= ilimit) {
    -            /* Fill Table */
    -            hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
    -                hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;  /* here because current+2 could be > iend-8 */
    -            hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
    -                hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
    -
    -            /* check immediate repcode */
    -            while ( (ip <= ilimit)
    -                 && ( (offset_2>0)
    -                 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
    -                /* store sequence */
    -                size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
    -                { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
    -                hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
    -                hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
    -                ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
    -                ip += rLength;
    -                anchor = ip;
    -                continue;   /* faster when present ... (?) */
    -    }   }   }
    -
    -    /* save reps for next block */
    -    seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
    -    seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
    -
    -    /* Last Literals */
    -    {   size_t const lastLLSize = iend - anchor;
    -        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    -        seqStorePtr->lit += lastLLSize;
    -    }
    -}
    -
    -
    -static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    -{
    -    const U32 mls = ctx->appliedParams.cParams.searchLength;
    -    switch(mls)
    -    {
    -    default: /* includes case 3 */
    -    case 4 :
    -        ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
    -    case 5 :
    -        ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
    -    case 6 :
    -        ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
    -    case 7 :
    -        ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
    -    }
    -}
    -
    -
    -static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
    -                                 const void* src, size_t srcSize,
    -                                 const U32 mls)
    -{
    -    U32* const hashLong = ctx->hashTable;
    -    U32  const hBitsL = ctx->appliedParams.cParams.hashLog;
    -    U32* const hashSmall = ctx->chainTable;
    -    U32  const hBitsS = ctx->appliedParams.cParams.chainLog;
    -    seqStore_t* seqStorePtr = &(ctx->seqStore);
    -    const BYTE* const base = ctx->base;
    -    const BYTE* const dictBase = ctx->dictBase;
    -    const BYTE* const istart = (const BYTE*)src;
    -    const BYTE* ip = istart;
    -    const BYTE* anchor = istart;
    -    const U32   lowestIndex = ctx->lowLimit;
    -    const BYTE* const dictStart = dictBase + lowestIndex;
    -    const U32   dictLimit = ctx->dictLimit;
    -    const BYTE* const lowPrefixPtr = base + dictLimit;
    -    const BYTE* const dictEnd = dictBase + dictLimit;
    -    const BYTE* const iend = istart + srcSize;
    -    const BYTE* const ilimit = iend - 8;
    -    U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
    -
    -    /* Search Loop */
    -    while (ip < ilimit) {  /* < instead of <=, because (ip+1) */
    -        const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
    -        const U32 matchIndex = hashSmall[hSmall];
    -        const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
    -        const BYTE* match = matchBase + matchIndex;
    -
    -        const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
    -        const U32 matchLongIndex = hashLong[hLong];
    -        const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
    -        const BYTE* matchLong = matchLongBase + matchLongIndex;
    -
    -        const U32 current = (U32)(ip-base);
    -        const U32 repIndex = current + 1 - offset_1;   /* offset_1 expected <= current +1 */
    -        const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
    -        const BYTE* repMatch = repBase + repIndex;
    -        size_t mLength;
    -        hashSmall[hSmall] = hashLong[hLong] = current;   /* update hash table */
    -
    -        if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
    -           && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
    -            const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
    -            mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
    -            ip++;
    -            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
    -        } else {
    -            if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
    -                const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
    -                const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
    -                U32 offset;
    -                mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
    -                offset = current - matchLongIndex;
    -                while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; }   /* catch up */
    -                offset_2 = offset_1;
    -                offset_1 = offset;
    -                ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
    -
    -            } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
    -                size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
    -                U32 const matchIndex3 = hashLong[h3];
    -                const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
    -                const BYTE* match3 = match3Base + matchIndex3;
    -                U32 offset;
    -                hashLong[h3] = current + 1;
    -                if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
    -                    const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
    -                    const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
    -                    mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
    -                    ip++;
    -                    offset = current+1 - matchIndex3;
    -                    while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
    -                } else {
    -                    const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
    -                    const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
    -                    mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
    -                    offset = current - matchIndex;
    -                    while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; }   /* catch up */
    -                }
    -                offset_2 = offset_1;
    -                offset_1 = offset;
    -                ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
    -
    -            } else {
    -                ip += ((ip-anchor) >> g_searchStrength) + 1;
    -                continue;
    -        }   }
    -
    -        /* found a match : store it */
    -        ip += mLength;
    -        anchor = ip;
    -
    -        if (ip <= ilimit) {
    -            /* Fill Table */
    -            hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
    -            hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
    -            hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
    -            hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
    -            /* check immediate repcode */
    -            while (ip <= ilimit) {
    -                U32 const current2 = (U32)(ip-base);
    -                U32 const repIndex2 = current2 - offset_2;
    -                const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
    -                if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex))  /* intentional overflow */
    -                   && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
    -                    const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
    -                    size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
    -                    U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */
    -                    ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
    -                    hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
    -                    hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
    -                    ip += repLength2;
    -                    anchor = ip;
    -                    continue;
    -                }
    -                break;
    -    }   }   }
    -
    -    /* save reps for next block */
    -    seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
    -
    -    /* Last Literals */
    -    {   size_t const lastLLSize = iend - anchor;
    -        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    -        seqStorePtr->lit += lastLLSize;
    -    }
    -}
    -
    -
    -static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
    -                         const void* src, size_t srcSize)
    -{
    -    U32 const mls = ctx->appliedParams.cParams.searchLength;
    -    switch(mls)
    -    {
    -    default: /* includes case 3 */
    -    case 4 :
    -        ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
    -    case 5 :
    -        ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
    -    case 6 :
    -        ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
    -    case 7 :
    -        ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
    -    }
    -}
    -
    -
    -/*-*************************************
    -*  Binary Tree search
    -***************************************/
    -/** ZSTD_insertBt1() : add one or multiple positions to tree.
    -*   ip : assumed <= iend-8 .
    -*   @return : nb of positions added */
    -static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
    -                          U32 extDict)
    -{
    -    U32*   const hashTable = zc->hashTable;
    -    U32    const hashLog = zc->appliedParams.cParams.hashLog;
    -    size_t const h  = ZSTD_hashPtr(ip, hashLog, mls);
    -    U32*   const bt = zc->chainTable;
    -    U32    const btLog  = zc->appliedParams.cParams.chainLog - 1;
    -    U32    const btMask = (1 << btLog) - 1;
    -    U32 matchIndex = hashTable[h];
    -    size_t commonLengthSmaller=0, commonLengthLarger=0;
    -    const BYTE* const base = zc->base;
    -    const BYTE* const dictBase = zc->dictBase;
    -    const U32 dictLimit = zc->dictLimit;
    -    const BYTE* const dictEnd = dictBase + dictLimit;
    -    const BYTE* const prefixStart = base + dictLimit;
    -    const BYTE* match;
    -    const U32 current = (U32)(ip-base);
    -    const U32 btLow = btMask >= current ? 0 : current - btMask;
    -    U32* smallerPtr = bt + 2*(current&btMask);
    -    U32* largerPtr  = smallerPtr + 1;
    -    U32 dummy32;   /* to be nullified at the end */
    -    U32 const windowLow = zc->lowLimit;
    -    U32 matchEndIdx = current+8;
    -    size_t bestLength = 8;
    -#ifdef ZSTD_C_PREDICT
    -    U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
    -    U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
    -    predictedSmall += (predictedSmall>0);
    -    predictedLarge += (predictedLarge>0);
    -#endif /* ZSTD_C_PREDICT */
    -
    -    hashTable[h] = current;   /* Update Hash Table */
    -
    -    while (nbCompares-- && (matchIndex > windowLow)) {
    -        U32* const nextPtr = bt + 2*(matchIndex & btMask);
    -        size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
    -
    -#ifdef ZSTD_C_PREDICT   /* note : can create issues when hlog small <= 11 */
    -        const U32* predictPtr = bt + 2*((matchIndex-1) & btMask);   /* written this way, as bt is a roll buffer */
    -        if (matchIndex == predictedSmall) {
    -            /* no need to check length, result known */
    -            *smallerPtr = matchIndex;
    -            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    -            smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */
    -            matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
    -            predictedSmall = predictPtr[1] + (predictPtr[1]>0);
    -            continue;
    -        }
    -        if (matchIndex == predictedLarge) {
    -            *largerPtr = matchIndex;
    -            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    -            largerPtr = nextPtr;
    -            matchIndex = nextPtr[0];
    -            predictedLarge = predictPtr[0] + (predictPtr[0]>0);
    -            continue;
    -        }
    -#endif
    -        if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
    -            match = base + matchIndex;
    -            if (match[matchLength] == ip[matchLength])
    -                matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
    -        } else {
    -            match = dictBase + matchIndex;
    -            matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
    -            if (matchIndex+matchLength >= dictLimit)
    -                match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */
    -        }
    -
    -        if (matchLength > bestLength) {
    -            bestLength = matchLength;
    -            if (matchLength > matchEndIdx - matchIndex)
    -                matchEndIdx = matchIndex + (U32)matchLength;
    -        }
    -
    -        if (ip+matchLength == iend)   /* equal : no way to know if inf or sup */
    -            break;   /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
    -
    -        if (match[matchLength] < ip[matchLength]) {  /* necessarily within correct buffer */
    -            /* match is smaller than current */
    -            *smallerPtr = matchIndex;             /* update smaller idx */
    -            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
    -            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    -            smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */
    -            matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
    -        } else {
    -            /* match is larger than current */
    -            *largerPtr = matchIndex;
    -            commonLengthLarger = matchLength;
    -            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    -            largerPtr = nextPtr;
    -            matchIndex = nextPtr[0];
    -    }   }
    -
    -    *smallerPtr = *largerPtr = 0;
    -    if (bestLength > 384) return MIN(192, (U32)(bestLength - 384));   /* speed optimization */
    -    if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
    -    return 1;
    -}
    -
    -
    -static size_t ZSTD_insertBtAndFindBestMatch (
    -                        ZSTD_CCtx* zc,
    -                        const BYTE* const ip, const BYTE* const iend,
    -                        size_t* offsetPtr,
    -                        U32 nbCompares, const U32 mls,
    -                        U32 extDict)
    -{
    -    U32*   const hashTable = zc->hashTable;
    -    U32    const hashLog = zc->appliedParams.cParams.hashLog;
    -    size_t const h  = ZSTD_hashPtr(ip, hashLog, mls);
    -    U32*   const bt = zc->chainTable;
    -    U32    const btLog  = zc->appliedParams.cParams.chainLog - 1;
    -    U32    const btMask = (1 << btLog) - 1;
    -    U32 matchIndex  = hashTable[h];
    -    size_t commonLengthSmaller=0, commonLengthLarger=0;
    -    const BYTE* const base = zc->base;
    -    const BYTE* const dictBase = zc->dictBase;
    -    const U32 dictLimit = zc->dictLimit;
    -    const BYTE* const dictEnd = dictBase + dictLimit;
    -    const BYTE* const prefixStart = base + dictLimit;
    -    const U32 current = (U32)(ip-base);
    -    const U32 btLow = btMask >= current ? 0 : current - btMask;
    -    const U32 windowLow = zc->lowLimit;
    -    U32* smallerPtr = bt + 2*(current&btMask);
    -    U32* largerPtr  = bt + 2*(current&btMask) + 1;
    -    U32 matchEndIdx = current+8;
    -    U32 dummy32;   /* to be nullified at the end */
    -    size_t bestLength = 0;
    -
    -    hashTable[h] = current;   /* Update Hash Table */
    -
    -    while (nbCompares-- && (matchIndex > windowLow)) {
    -        U32* const nextPtr = bt + 2*(matchIndex & btMask);
    -        size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
    -        const BYTE* match;
    -
    -        if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
    -            match = base + matchIndex;
    -            if (match[matchLength] == ip[matchLength])
    -                matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
    -        } else {
    -            match = dictBase + matchIndex;
    -            matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
    -            if (matchIndex+matchLength >= dictLimit)
    -                match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */
    -        }
    -
    -        if (matchLength > bestLength) {
    -            if (matchLength > matchEndIdx - matchIndex)
    -                matchEndIdx = matchIndex + (U32)matchLength;
    -            if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
    -                bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
    -            if (ip+matchLength == iend)   /* equal : no way to know if inf or sup */
    -                break;   /* drop, to guarantee consistency (miss a little bit of compression) */
    -        }
    -
    -        if (match[matchLength] < ip[matchLength]) {
    -            /* match is smaller than current */
    -            *smallerPtr = matchIndex;             /* update smaller idx */
    -            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
    -            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    -            smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */
    -            matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
    -        } else {
    -            /* match is larger than current */
    -            *largerPtr = matchIndex;
    -            commonLengthLarger = matchLength;
    -            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    -            largerPtr = nextPtr;
    -            matchIndex = nextPtr[0];
    -    }   }
    -
    -    *smallerPtr = *largerPtr = 0;
    -
    -    zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
    -    return bestLength;
    -}
    -
    -
    -static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
    -{
    -    const BYTE* const base = zc->base;
    -    const U32 target = (U32)(ip - base);
    -    U32 idx = zc->nextToUpdate;
    -
    -    while(idx < target)
    -        idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
    -}
    -
    -/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
    -static size_t ZSTD_BtFindBestMatch (
    -                        ZSTD_CCtx* zc,
    -                        const BYTE* const ip, const BYTE* const iLimit,
    -                        size_t* offsetPtr,
    -                        const U32 maxNbAttempts, const U32 mls)
    -{
    -    if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */
    -    ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
    -    return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
    -}
    -
    -
    -static size_t ZSTD_BtFindBestMatch_selectMLS (
    -                        ZSTD_CCtx* zc,   /* Index table will be updated */
    -                        const BYTE* ip, const BYTE* const iLimit,
    -                        size_t* offsetPtr,
    -                        const U32 maxNbAttempts, const U32 matchLengthSearch)
    -{
    -    switch(matchLengthSearch)
    -    {
    -    default : /* includes case 3 */
    -    case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
    -    case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
    -    case 7 :
    -    case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
    -    }
    -}
    -
    -
    -static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
    -{
    -    const BYTE* const base = zc->base;
    -    const U32 target = (U32)(ip - base);
    -    U32 idx = zc->nextToUpdate;
    -
    -    while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
    -}
    -
    -
    -/** Tree updater, providing best match */
    -static size_t ZSTD_BtFindBestMatch_extDict (
    -                        ZSTD_CCtx* zc,
    -                        const BYTE* const ip, const BYTE* const iLimit,
    -                        size_t* offsetPtr,
    -                        const U32 maxNbAttempts, const U32 mls)
    -{
    -    if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */
    -    ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
    -    return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
    -}
    -
    -
    -static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
    -                        ZSTD_CCtx* zc,   /* Index table will be updated */
    -                        const BYTE* ip, const BYTE* const iLimit,
    -                        size_t* offsetPtr,
    -                        const U32 maxNbAttempts, const U32 matchLengthSearch)
    -{
    -    switch(matchLengthSearch)
    -    {
    -    default : /* includes case 3 */
    -    case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
    -    case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
    -    case 7 :
    -    case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
    -    }
    -}
    -
    -
    -
    -/* *********************************
    -*  Hash Chain
    -***********************************/
    -#define NEXT_IN_CHAIN(d, mask)   chainTable[(d) & mask]
    -
    -/* Update chains up to ip (excluded)
    -   Assumption : always within prefix (i.e. not within extDict) */
    -FORCE_INLINE_TEMPLATE
    -U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
    -{
    -    U32* const hashTable  = zc->hashTable;
    -    const U32 hashLog = zc->appliedParams.cParams.hashLog;
    -    U32* const chainTable = zc->chainTable;
    -    const U32 chainMask = (1 << zc->appliedParams.cParams.chainLog) - 1;
    -    const BYTE* const base = zc->base;
    -    const U32 target = (U32)(ip - base);
    -    U32 idx = zc->nextToUpdate;
    -
    -    while(idx < target) { /* catch up */
    -        size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
    -        NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
    -        hashTable[h] = idx;
    -        idx++;
    -    }
    -
    -    zc->nextToUpdate = target;
    -    return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
    -}
    -
    -
    -/* inlining is important to hardwire a hot branch (template emulation) */
    -FORCE_INLINE_TEMPLATE
    -size_t ZSTD_HcFindBestMatch_generic (
    -                        ZSTD_CCtx* zc,   /* Index table will be updated */
    -                        const BYTE* const ip, const BYTE* const iLimit,
    -                        size_t* offsetPtr,
    -                        const U32 maxNbAttempts, const U32 mls, const U32 extDict)
    -{
    -    U32* const chainTable = zc->chainTable;
    -    const U32 chainSize = (1 << zc->appliedParams.cParams.chainLog);
    -    const U32 chainMask = chainSize-1;
    -    const BYTE* const base = zc->base;
    -    const BYTE* const dictBase = zc->dictBase;
    -    const U32 dictLimit = zc->dictLimit;
    -    const BYTE* const prefixStart = base + dictLimit;
    -    const BYTE* const dictEnd = dictBase + dictLimit;
    -    const U32 lowLimit = zc->lowLimit;
    -    const U32 current = (U32)(ip-base);
    -    const U32 minChain = current > chainSize ? current - chainSize : 0;
    -    int nbAttempts=maxNbAttempts;
    -    size_t ml=4-1;
    -
    -    /* HC4 match finder */
    -    U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
    -
    -    for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
    -        const BYTE* match;
    -        size_t currentMl=0;
    -        if ((!extDict) || matchIndex >= dictLimit) {
    -            match = base + matchIndex;
    -            if (match[ml] == ip[ml])   /* potentially better */
    -                currentMl = ZSTD_count(ip, match, iLimit);
    -        } else {
    -            match = dictBase + matchIndex;
    -            if (MEM_read32(match) == MEM_read32(ip))   /* assumption : matchIndex <= dictLimit-4 (by table construction) */
    -                currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
    -        }
    -
    -        /* save best solution */
    -        if (currentMl > ml) {
    -            ml = currentMl;
    -            *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
    -            if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
    -        }
    -
    -        if (matchIndex <= minChain) break;
    -        matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
    -    }
    -
    -    return ml;
    -}
    -
    -
    -FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
    -                        ZSTD_CCtx* zc,
    -                        const BYTE* ip, const BYTE* const iLimit,
    -                        size_t* offsetPtr,
    -                        const U32 maxNbAttempts, const U32 matchLengthSearch)
    -{
    -    switch(matchLengthSearch)
    -    {
    -    default : /* includes case 3 */
    -    case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
    -    case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
    -    case 7 :
    -    case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
    -    }
    -}
    -
    -
    -FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
    -                        ZSTD_CCtx* zc,
    -                        const BYTE* ip, const BYTE* const iLimit,
    -                        size_t* offsetPtr,
    -                        const U32 maxNbAttempts, const U32 matchLengthSearch)
    -{
    -    switch(matchLengthSearch)
    -    {
    -    default : /* includes case 3 */
    -    case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
    -    case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
    -    case 7 :
    -    case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
    -    }
    -}
    -
    -
    -/* *******************************
    -*  Common parser - lazy strategy
    -*********************************/
    -FORCE_INLINE_TEMPLATE
    -void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
    -                                     const void* src, size_t srcSize,
    -                                     const U32 searchMethod, const U32 depth)
    -{
    -    seqStore_t* seqStorePtr = &(ctx->seqStore);
    -    const BYTE* const istart = (const BYTE*)src;
    -    const BYTE* ip = istart;
    -    const BYTE* anchor = istart;
    -    const BYTE* const iend = istart + srcSize;
    -    const BYTE* const ilimit = iend - 8;
    -    const BYTE* const base = ctx->base + ctx->dictLimit;
    -
    -    U32 const maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
    -    U32 const mls = ctx->appliedParams.cParams.searchLength;
    -
    -    typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
    -                        size_t* offsetPtr,
    -                        U32 maxNbAttempts, U32 matchLengthSearch);
    -    searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
    -    U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1], savedOffset=0;
    -
    -    /* init */
    -    ip += (ip==base);
    -    ctx->nextToUpdate3 = ctx->nextToUpdate;
    -    {   U32 const maxRep = (U32)(ip-base);
    -        if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
    -        if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
    -    }
    -
    -    /* Match Loop */
    -    while (ip < ilimit) {
    -        size_t matchLength=0;
    -        size_t offset=0;
    -        const BYTE* start=ip+1;
    -
    -        /* check repCode */
    -        if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
    -            /* repcode : we take it */
    -            matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
    -            if (depth==0) goto _storeSequence;
    -        }
    -
    -        /* first search (depth 0) */
    -        {   size_t offsetFound = 99999999;
    -            size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
    -            if (ml2 > matchLength)
    -                matchLength = ml2, start = ip, offset=offsetFound;
    -        }
    -
    -        if (matchLength < 4) {
    -            ip += ((ip-anchor) >> g_searchStrength) + 1;   /* jump faster over incompressible sections */
    -            continue;
    -        }
    -
    -        /* let's try to find a better solution */
    -        if (depth>=1)
    -        while (ip0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
    -                size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
    -                int const gain2 = (int)(mlRep * 3);
    -                int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
    -                if ((mlRep >= 4) && (gain2 > gain1))
    -                    matchLength = mlRep, offset = 0, start = ip;
    -            }
    -            {   size_t offset2=99999999;
    -                size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
    -                int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */
    -                int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
    -                if ((ml2 >= 4) && (gain2 > gain1)) {
    -                    matchLength = ml2, offset = offset2, start = ip;
    -                    continue;   /* search a better one */
    -            }   }
    -
    -            /* let's find an even better one */
    -            if ((depth==2) && (ip0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
    -                    size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
    -                    int const gain2 = (int)(ml2 * 4);
    -                    int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
    -                    if ((ml2 >= 4) && (gain2 > gain1))
    -                        matchLength = ml2, offset = 0, start = ip;
    -                }
    -                {   size_t offset2=99999999;
    -                    size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
    -                    int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */
    -                    int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
    -                    if ((ml2 >= 4) && (gain2 > gain1)) {
    -                        matchLength = ml2, offset = offset2, start = ip;
    -                        continue;
    -            }   }   }
    -            break;  /* nothing found : store previous solution */
    -        }
    -
    -        /* NOTE:
    -         * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior.
    -         * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which
    -         * overflows the pointer, which is undefined behavior.
    -         */
    -        /* catch up */
    -        if (offset) {
    -            while ( (start > anchor)
    -                 && (start > base+offset-ZSTD_REP_MOVE)
    -                 && (start[-1] == (start-offset+ZSTD_REP_MOVE)[-1]) )  /* only search for offset within prefix */
    -                { start--; matchLength++; }
    -            offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
    -        }
    -        /* store sequence */
    -_storeSequence:
    -        {   size_t const litLength = start - anchor;
    -            ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
    -            anchor = ip = start + matchLength;
    -        }
    -
    -        /* check immediate repcode */
    -        while ( (ip <= ilimit)
    -             && ((offset_2>0)
    -             & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
    -            /* store sequence */
    -            matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
    -            offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
    -            ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
    -            ip += matchLength;
    -            anchor = ip;
    -            continue;   /* faster when present ... (?) */
    -    }   }
    -
    -    /* Save reps for next block */
    -    seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
    -    seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
    -
    -    /* Last Literals */
    -    {   size_t const lastLLSize = iend - anchor;
    -        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    -        seqStorePtr->lit += lastLLSize;
    -    }
    -}
    -
    -
    -static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    -{
    -    ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
    -}
    -
    -static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    -{
    -    ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
    -}
    -
    -static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    -{
    -    ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
    -}
    -
    -static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    -{
    -    ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
    -}
    -
    -
    -FORCE_INLINE_TEMPLATE
    -void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
    -                                     const void* src, size_t srcSize,
    -                                     const U32 searchMethod, const U32 depth)
    -{
    -    seqStore_t* seqStorePtr = &(ctx->seqStore);
    -    const BYTE* const istart = (const BYTE*)src;
    -    const BYTE* ip = istart;
    -    const BYTE* anchor = istart;
    -    const BYTE* const iend = istart + srcSize;
    -    const BYTE* const ilimit = iend - 8;
    -    const BYTE* const base = ctx->base;
    -    const U32 dictLimit = ctx->dictLimit;
    -    const U32 lowestIndex = ctx->lowLimit;
    -    const BYTE* const prefixStart = base + dictLimit;
    -    const BYTE* const dictBase = ctx->dictBase;
    -    const BYTE* const dictEnd  = dictBase + dictLimit;
    -    const BYTE* const dictStart  = dictBase + ctx->lowLimit;
    -
    -    const U32 maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
    -    const U32 mls = ctx->appliedParams.cParams.searchLength;
    -
    -    typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
    -                        size_t* offsetPtr,
    -                        U32 maxNbAttempts, U32 matchLengthSearch);
    -    searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
    -
    -    U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1];
    -
    -    /* init */
    -    ctx->nextToUpdate3 = ctx->nextToUpdate;
    -    ip += (ip == prefixStart);
    -
    -    /* Match Loop */
    -    while (ip < ilimit) {
    -        size_t matchLength=0;
    -        size_t offset=0;
    -        const BYTE* start=ip+1;
    -        U32 current = (U32)(ip-base);
    -
    -        /* check repCode */
    -        {   const U32 repIndex = (U32)(current+1 - offset_1);
    -            const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
    -            const BYTE* const repMatch = repBase + repIndex;
    -            if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))   /* intentional overflow */
    -            if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
    -                /* repcode detected we should take it */
    -                const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
    -                matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
    -                if (depth==0) goto _storeSequence;
    -        }   }
    -
    -        /* first search (depth 0) */
    -        {   size_t offsetFound = 99999999;
    -            size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
    -            if (ml2 > matchLength)
    -                matchLength = ml2, start = ip, offset=offsetFound;
    -        }
    -
    -         if (matchLength < 4) {
    -            ip += ((ip-anchor) >> g_searchStrength) + 1;   /* jump faster over incompressible sections */
    -            continue;
    -        }
    -
    -        /* let's try to find a better solution */
    -        if (depth>=1)
    -        while (ip= 3) & (repIndex > lowestIndex))  /* intentional overflow */
    -                if (MEM_read32(ip) == MEM_read32(repMatch)) {
    -                    /* repcode detected */
    -                    const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
    -                    size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
    -                    int const gain2 = (int)(repLength * 3);
    -                    int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
    -                    if ((repLength >= 4) && (gain2 > gain1))
    -                        matchLength = repLength, offset = 0, start = ip;
    -            }   }
    -
    -            /* search match, depth 1 */
    -            {   size_t offset2=99999999;
    -                size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
    -                int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */
    -                int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
    -                if ((ml2 >= 4) && (gain2 > gain1)) {
    -                    matchLength = ml2, offset = offset2, start = ip;
    -                    continue;   /* search a better one */
    -            }   }
    -
    -            /* let's find an even better one */
    -            if ((depth==2) && (ip= 3) & (repIndex > lowestIndex))  /* intentional overflow */
    -                    if (MEM_read32(ip) == MEM_read32(repMatch)) {
    -                        /* repcode detected */
    -                        const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
    -                        size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
    -                        int const gain2 = (int)(repLength * 4);
    -                        int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
    -                        if ((repLength >= 4) && (gain2 > gain1))
    -                            matchLength = repLength, offset = 0, start = ip;
    -                }   }
    -
    -                /* search match, depth 2 */
    -                {   size_t offset2=99999999;
    -                    size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
    -                    int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */
    -                    int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
    -                    if ((ml2 >= 4) && (gain2 > gain1)) {
    -                        matchLength = ml2, offset = offset2, start = ip;
    -                        continue;
    -            }   }   }
    -            break;  /* nothing found : store previous solution */
    -        }
    -
    -        /* catch up */
    -        if (offset) {
    -            U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
    -            const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
    -            const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
    -            while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; }  /* catch up */
    -            offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
    -        }
    -
    -        /* store sequence */
    -_storeSequence:
    -        {   size_t const litLength = start - anchor;
    -            ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
    -            anchor = ip = start + matchLength;
    -        }
    -
    -        /* check immediate repcode */
    -        while (ip <= ilimit) {
    -            const U32 repIndex = (U32)((ip-base) - offset_2);
    -            const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
    -            const BYTE* const repMatch = repBase + repIndex;
    -            if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))  /* intentional overflow */
    -            if (MEM_read32(ip) == MEM_read32(repMatch)) {
    -                /* repcode detected we should take it */
    -                const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
    -                matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
    -                offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset;   /* swap offset history */
    -                ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
    -                ip += matchLength;
    -                anchor = ip;
    -                continue;   /* faster when present ... (?) */
    -            }
    -            break;
    -    }   }
    -
    -    /* Save reps for next block */
    -    seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
    -
    -    /* Last Literals */
    -    {   size_t const lastLLSize = iend - anchor;
    -        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    -        seqStorePtr->lit += lastLLSize;
    -    }
    -}
    -
    -
    -void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    -{
    -    ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
    -}
    -
    -static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    -{
    -    ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
    -}
    -
    -static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    -{
    -    ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
    -}
    -
    -static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    -{
    -    ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
    -}
    -
    -
    -/* The optimal parser */
    -#include "zstd_opt.h"
    -
    -static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    -{
    -#ifdef ZSTD_OPT_H_91842398743
    -    ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
    -#else
    -    (void)ctx; (void)src; (void)srcSize;
    -    return;
    -#endif
    -}
    -
    -static void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    -{
    -#ifdef ZSTD_OPT_H_91842398743
    -    ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
    -#else
    -    (void)ctx; (void)src; (void)srcSize;
    -    return;
    -#endif
    -}
    -
    -static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    -{
    -#ifdef ZSTD_OPT_H_91842398743
    -    ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
    -#else
    -    (void)ctx; (void)src; (void)srcSize;
    -    return;
    -#endif
    -}
    -
    -static void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    -{
    -#ifdef ZSTD_OPT_H_91842398743
    -    ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
    -#else
    -    (void)ctx; (void)src; (void)srcSize;
    -    return;
    -#endif
    -}
    -
    -
     /* ZSTD_selectBlockCompressor() :
      * assumption : strat is a valid strategy */
     typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
    diff --git a/lib/compress/zstd_compress.h b/lib/compress/zstd_compress.h
    new file mode 100644
    index 000000000..a136a949d
    --- /dev/null
    +++ b/lib/compress/zstd_compress.h
    @@ -0,0 +1,301 @@
    +/*
    + * 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).
    + */
    +
    +
    +#ifndef ZSTD_COMPRESS_H
    +#define ZSTD_COMPRESS_H
    +
    +/*-*************************************
    +*  Dependencies
    +***************************************/
    +#include "zstd_internal.h"
    +#include "zstdmt_compress.h"
    +
    +#if defined (__cplusplus)
    +extern "C" {
    +#endif
    +
    +/*-*************************************
    +*  Constants
    +***************************************/
    +static const U32 g_searchStrength = 8;
    +#define HASH_READ_SIZE 8
    +
    +
    +/*-*************************************
    +*  Context memory management
    +***************************************/
    +typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
    +typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage;
    +
    +typedef struct ZSTD_prefixDict_s {
    +    const void* dict;
    +    size_t dictSize;
    +    ZSTD_dictMode_e dictMode;
    +} ZSTD_prefixDict;
    +
    +struct ZSTD_CCtx_s {
    +    const BYTE* nextSrc;    /* next block here to continue on current prefix */
    +    const BYTE* base;       /* All regular indexes relative to this position */
    +    const BYTE* dictBase;   /* extDict indexes relative to this position */
    +    U32   dictLimit;        /* below that point, need extDict */
    +    U32   lowLimit;         /* below that point, no more data */
    +    U32   nextToUpdate;     /* index from which to continue dictionary update */
    +    U32   nextToUpdate3;    /* index from which to continue dictionary update */
    +    U32   hashLog3;         /* dispatch table : larger == faster, more memory */
    +    U32   loadedDictEnd;    /* index of end of dictionary */
    +    ZSTD_compressionStage_e stage;
    +    U32   dictID;
    +    ZSTD_CCtx_params requestedParams;
    +    ZSTD_CCtx_params appliedParams;
    +    void* workSpace;
    +    size_t workSpaceSize;
    +    size_t blockSize;
    +    U64 pledgedSrcSizePlusOne;  /* this way, 0 (default) == unknown */
    +    U64 consumedSrcSize;
    +    XXH64_state_t xxhState;
    +    ZSTD_customMem customMem;
    +    size_t staticSize;
    +
    +    seqStore_t seqStore;    /* sequences storage ptrs */
    +    optState_t optState;
    +    U32* hashTable;
    +    U32* hashTable3;
    +    U32* chainTable;
    +    ZSTD_entropyCTables_t* entropy;
    +
    +    /* streaming */
    +    char*  inBuff;
    +    size_t inBuffSize;
    +    size_t inToCompress;
    +    size_t inBuffPos;
    +    size_t inBuffTarget;
    +    char*  outBuff;
    +    size_t outBuffSize;
    +    size_t outBuffContentSize;
    +    size_t outBuffFlushedSize;
    +    ZSTD_cStreamStage streamStage;
    +    U32    frameEnded;
    +
    +    /* Dictionary */
    +    ZSTD_CDict* cdictLocal;
    +    const ZSTD_CDict* cdict;
    +    ZSTD_prefixDict prefixDict;   /* single-usage dictionary */
    +
    +    /* Multi-threading */
    +    ZSTDMT_CCtx* mtctx;
    +};
    +
    +
    +static const BYTE LL_Code[64] = {  0,  1,  2,  3,  4,  5,  6,  7,
    +                                   8,  9, 10, 11, 12, 13, 14, 15,
    +                                  16, 16, 17, 17, 18, 18, 19, 19,
    +                                  20, 20, 20, 20, 21, 21, 21, 21,
    +                                  22, 22, 22, 22, 22, 22, 22, 22,
    +                                  23, 23, 23, 23, 23, 23, 23, 23,
    +                                  24, 24, 24, 24, 24, 24, 24, 24,
    +                                  24, 24, 24, 24, 24, 24, 24, 24 };
    +
    +static const BYTE ML_Code[128] = { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
    +                                  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
    +                                  32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
    +                                  38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
    +                                  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
    +                                  41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
    +                                  42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
    +                                  42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
    +
    +/*! ZSTD_storeSeq() :
    +    Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
    +    `offsetCode` : distance to match, or 0 == repCode.
    +    `matchCode` : matchLength - MINMATCH
    +*/
    +MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode)
    +{
    +#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6)
    +    static const BYTE* g_start = NULL;
    +    U32 const pos = (U32)((const BYTE*)literals - g_start);
    +    if (g_start==NULL) g_start = (const BYTE*)literals;
    +    if ((pos > 0) && (pos < 1000000000))
    +        DEBUGLOG(6, "Cpos %6u :%5u literals & match %3u bytes at distance %6u",
    +               pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
    +#endif
    +    /* copy Literals */
    +    assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + 128 KB);
    +    ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
    +    seqStorePtr->lit += litLength;
    +
    +    /* literal Length */
    +    if (litLength>0xFFFF) {
    +        seqStorePtr->longLengthID = 1;
    +        seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
    +    }
    +    seqStorePtr->sequences[0].litLength = (U16)litLength;
    +
    +    /* match offset */
    +    seqStorePtr->sequences[0].offset = offsetCode + 1;
    +
    +    /* match Length */
    +    if (matchCode>0xFFFF) {
    +        seqStorePtr->longLengthID = 2;
    +        seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
    +    }
    +    seqStorePtr->sequences[0].matchLength = (U16)matchCode;
    +
    +    seqStorePtr->sequences++;
    +}
    +
    +
    +/*-*************************************
    +*  Match length counter
    +***************************************/
    +static unsigned ZSTD_NbCommonBytes (register size_t val)
    +{
    +    if (MEM_isLittleEndian()) {
    +        if (MEM_64bits()) {
    +#       if defined(_MSC_VER) && defined(_WIN64)
    +            unsigned long r = 0;
    +            _BitScanForward64( &r, (U64)val );
    +            return (unsigned)(r>>3);
    +#       elif defined(__GNUC__) && (__GNUC__ >= 3)
    +            return (__builtin_ctzll((U64)val) >> 3);
    +#       else
    +            static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
    +                                                     0, 3, 1, 3, 1, 4, 2, 7,
    +                                                     0, 2, 3, 6, 1, 5, 3, 5,
    +                                                     1, 3, 4, 4, 2, 5, 6, 7,
    +                                                     7, 0, 1, 2, 3, 3, 4, 6,
    +                                                     2, 6, 5, 5, 3, 4, 5, 6,
    +                                                     7, 1, 2, 4, 6, 4, 4, 5,
    +                                                     7, 2, 6, 5, 7, 6, 7, 7 };
    +            return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
    +#       endif
    +        } else { /* 32 bits */
    +#       if defined(_MSC_VER)
    +            unsigned long r=0;
    +            _BitScanForward( &r, (U32)val );
    +            return (unsigned)(r>>3);
    +#       elif defined(__GNUC__) && (__GNUC__ >= 3)
    +            return (__builtin_ctz((U32)val) >> 3);
    +#       else
    +            static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
    +                                                     3, 2, 2, 1, 3, 2, 0, 1,
    +                                                     3, 3, 1, 2, 2, 2, 2, 0,
    +                                                     3, 1, 2, 0, 1, 0, 1, 1 };
    +            return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
    +#       endif
    +        }
    +    } else {  /* Big Endian CPU */
    +        if (MEM_64bits()) {
    +#       if defined(_MSC_VER) && defined(_WIN64)
    +            unsigned long r = 0;
    +            _BitScanReverse64( &r, val );
    +            return (unsigned)(r>>3);
    +#       elif defined(__GNUC__) && (__GNUC__ >= 3)
    +            return (__builtin_clzll(val) >> 3);
    +#       else
    +            unsigned r;
    +            const unsigned n32 = sizeof(size_t)*4;   /* calculate this way due to compiler complaining in 32-bits mode */
    +            if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
    +            if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
    +            r += (!val);
    +            return r;
    +#       endif
    +        } else { /* 32 bits */
    +#       if defined(_MSC_VER)
    +            unsigned long r = 0;
    +            _BitScanReverse( &r, (unsigned long)val );
    +            return (unsigned)(r>>3);
    +#       elif defined(__GNUC__) && (__GNUC__ >= 3)
    +            return (__builtin_clz((U32)val) >> 3);
    +#       else
    +            unsigned r;
    +            if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
    +            r += (!val);
    +            return r;
    +#       endif
    +    }   }
    +}
    +
    +
    +MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
    +{
    +    const BYTE* const pStart = pIn;
    +    const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
    +
    +    while (pIn < pInLoopLimit) {
    +        size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
    +        if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
    +        pIn += ZSTD_NbCommonBytes(diff);
    +        return (size_t)(pIn - pStart);
    +    }
    +    if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
    +    if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
    +    if ((pIn> (32-h) ; }
    +MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
    +
    +static const U32 prime4bytes = 2654435761U;
    +static U32    ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
    +static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
    +
    +static const U64 prime5bytes = 889523592379ULL;
    +static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u  << (64-40)) * prime5bytes) >> (64-h)) ; }
    +static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
    +
    +static const U64 prime6bytes = 227718039650203ULL;
    +static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u  << (64-48)) * prime6bytes) >> (64-h)) ; }
    +static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
    +
    +static const U64 prime7bytes = 58295818150454627ULL;
    +static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u  << (64-56)) * prime7bytes) >> (64-h)) ; }
    +static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
    +
    +static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
    +static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
    +static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
    +
    +MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
    +{
    +    switch(mls)
    +    {
    +    default:
    +    case 4: return ZSTD_hash4Ptr(p, hBits);
    +    case 5: return ZSTD_hash5Ptr(p, hBits);
    +    case 6: return ZSTD_hash6Ptr(p, hBits);
    +    case 7: return ZSTD_hash7Ptr(p, hBits);
    +    case 8: return ZSTD_hash8Ptr(p, hBits);
    +    }
    +}
    +
    +#if defined (__cplusplus)
    +}
    +#endif
    +
    +#endif /* ZSTD_COMPRESS_H */
    diff --git a/lib/compress/zstd_double_fast.c b/lib/compress/zstd_double_fast.c
    new file mode 100644
    index 000000000..437e9a2c6
    --- /dev/null
    +++ b/lib/compress/zstd_double_fast.c
    @@ -0,0 +1,313 @@
    +/*
    + * 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).
    + */
    +
    +#include "zstd_double_fast.h"
    +
    +
    +void ZSTD_fillDoubleHashTable(ZSTD_CCtx* cctx, const void* end, const U32 mls)
    +{
    +    U32* const hashLarge = cctx->hashTable;
    +    U32  const hBitsL = cctx->appliedParams.cParams.hashLog;
    +    U32* const hashSmall = cctx->chainTable;
    +    U32  const hBitsS = cctx->appliedParams.cParams.chainLog;
    +    const BYTE* const base = cctx->base;
    +    const BYTE* ip = base + cctx->nextToUpdate;
    +    const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
    +    const size_t fastHashFillStep = 3;
    +
    +    while(ip <= iend) {
    +        hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
    +        hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
    +        ip += fastHashFillStep;
    +    }
    +}
    +
    +
    +FORCE_INLINE_TEMPLATE
    +void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
    +                                 const void* src, size_t srcSize,
    +                                 const U32 mls)
    +{
    +    U32* const hashLong = cctx->hashTable;
    +    const U32 hBitsL = cctx->appliedParams.cParams.hashLog;
    +    U32* const hashSmall = cctx->chainTable;
    +    const U32 hBitsS = cctx->appliedParams.cParams.chainLog;
    +    seqStore_t* seqStorePtr = &(cctx->seqStore);
    +    const BYTE* const base = cctx->base;
    +    const BYTE* const istart = (const BYTE*)src;
    +    const BYTE* ip = istart;
    +    const BYTE* anchor = istart;
    +    const U32 lowestIndex = cctx->dictLimit;
    +    const BYTE* const lowest = base + lowestIndex;
    +    const BYTE* const iend = istart + srcSize;
    +    const BYTE* const ilimit = iend - HASH_READ_SIZE;
    +    U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
    +    U32 offsetSaved = 0;
    +
    +    /* init */
    +    ip += (ip==lowest);
    +    {   U32 const maxRep = (U32)(ip-lowest);
    +        if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
    +        if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
    +    }
    +
    +    /* Main Search Loop */
    +    while (ip < ilimit) {   /* < instead of <=, because repcode check at (ip+1) */
    +        size_t mLength;
    +        size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
    +        size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
    +        U32 const current = (U32)(ip-base);
    +        U32 const matchIndexL = hashLong[h2];
    +        U32 const matchIndexS = hashSmall[h];
    +        const BYTE* matchLong = base + matchIndexL;
    +        const BYTE* match = base + matchIndexS;
    +        hashLong[h2] = hashSmall[h] = current;   /* update hash tables */
    +
    +        assert(offset_1 <= current);   /* supposed guaranteed by construction */
    +        if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
    +            /* favor repcode */
    +            mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
    +            ip++;
    +            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
    +        } else {
    +            U32 offset;
    +            if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
    +                mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
    +                offset = (U32)(ip-matchLong);
    +                while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
    +            } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
    +                size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
    +                U32 const matchIndexL3 = hashLong[hl3];
    +                const BYTE* matchL3 = base + matchIndexL3;
    +                hashLong[hl3] = current + 1;
    +                if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
    +                    mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
    +                    ip++;
    +                    offset = (U32)(ip-matchL3);
    +                    while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
    +                } else {
    +                    mLength = ZSTD_count(ip+4, match+4, iend) + 4;
    +                    offset = (U32)(ip-match);
    +                    while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
    +                }
    +            } else {
    +                ip += ((ip-anchor) >> g_searchStrength) + 1;
    +                continue;
    +            }
    +
    +            offset_2 = offset_1;
    +            offset_1 = offset;
    +
    +            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
    +        }
    +
    +        /* match found */
    +        ip += mLength;
    +        anchor = ip;
    +
    +        if (ip <= ilimit) {
    +            /* Fill Table */
    +            hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
    +                hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;  /* here because current+2 could be > iend-8 */
    +            hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
    +                hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
    +
    +            /* check immediate repcode */
    +            while ( (ip <= ilimit)
    +                 && ( (offset_2>0)
    +                 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
    +                /* store sequence */
    +                size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
    +                { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
    +                hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
    +                hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
    +                ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
    +                ip += rLength;
    +                anchor = ip;
    +                continue;   /* faster when present ... (?) */
    +    }   }   }
    +
    +    /* save reps for next block */
    +    seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
    +    seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
    +
    +    /* Last Literals */
    +    {   size_t const lastLLSize = iend - anchor;
    +        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    +        seqStorePtr->lit += lastLLSize;
    +    }
    +}
    +
    +
    +void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    +{
    +    const U32 mls = ctx->appliedParams.cParams.searchLength;
    +    switch(mls)
    +    {
    +    default: /* includes case 3 */
    +    case 4 :
    +        ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
    +    case 5 :
    +        ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
    +    case 6 :
    +        ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
    +    case 7 :
    +        ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
    +    }
    +}
    +
    +
    +static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
    +                                 const void* src, size_t srcSize,
    +                                 const U32 mls)
    +{
    +    U32* const hashLong = ctx->hashTable;
    +    U32  const hBitsL = ctx->appliedParams.cParams.hashLog;
    +    U32* const hashSmall = ctx->chainTable;
    +    U32  const hBitsS = ctx->appliedParams.cParams.chainLog;
    +    seqStore_t* seqStorePtr = &(ctx->seqStore);
    +    const BYTE* const base = ctx->base;
    +    const BYTE* const dictBase = ctx->dictBase;
    +    const BYTE* const istart = (const BYTE*)src;
    +    const BYTE* ip = istart;
    +    const BYTE* anchor = istart;
    +    const U32   lowestIndex = ctx->lowLimit;
    +    const BYTE* const dictStart = dictBase + lowestIndex;
    +    const U32   dictLimit = ctx->dictLimit;
    +    const BYTE* const lowPrefixPtr = base + dictLimit;
    +    const BYTE* const dictEnd = dictBase + dictLimit;
    +    const BYTE* const iend = istart + srcSize;
    +    const BYTE* const ilimit = iend - 8;
    +    U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
    +
    +    /* Search Loop */
    +    while (ip < ilimit) {  /* < instead of <=, because (ip+1) */
    +        const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
    +        const U32 matchIndex = hashSmall[hSmall];
    +        const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
    +        const BYTE* match = matchBase + matchIndex;
    +
    +        const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
    +        const U32 matchLongIndex = hashLong[hLong];
    +        const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
    +        const BYTE* matchLong = matchLongBase + matchLongIndex;
    +
    +        const U32 current = (U32)(ip-base);
    +        const U32 repIndex = current + 1 - offset_1;   /* offset_1 expected <= current +1 */
    +        const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
    +        const BYTE* repMatch = repBase + repIndex;
    +        size_t mLength;
    +        hashSmall[hSmall] = hashLong[hLong] = current;   /* update hash table */
    +
    +        if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
    +           && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
    +            const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
    +            mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
    +            ip++;
    +            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
    +        } else {
    +            if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
    +                const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
    +                const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
    +                U32 offset;
    +                mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
    +                offset = current - matchLongIndex;
    +                while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; }   /* catch up */
    +                offset_2 = offset_1;
    +                offset_1 = offset;
    +                ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
    +
    +            } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
    +                size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
    +                U32 const matchIndex3 = hashLong[h3];
    +                const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
    +                const BYTE* match3 = match3Base + matchIndex3;
    +                U32 offset;
    +                hashLong[h3] = current + 1;
    +                if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
    +                    const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
    +                    const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
    +                    mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
    +                    ip++;
    +                    offset = current+1 - matchIndex3;
    +                    while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
    +                } else {
    +                    const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
    +                    const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
    +                    mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
    +                    offset = current - matchIndex;
    +                    while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; }   /* catch up */
    +                }
    +                offset_2 = offset_1;
    +                offset_1 = offset;
    +                ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
    +
    +            } else {
    +                ip += ((ip-anchor) >> g_searchStrength) + 1;
    +                continue;
    +        }   }
    +
    +        /* found a match : store it */
    +        ip += mLength;
    +        anchor = ip;
    +
    +        if (ip <= ilimit) {
    +            /* Fill Table */
    +            hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
    +            hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
    +            hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
    +            hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
    +            /* check immediate repcode */
    +            while (ip <= ilimit) {
    +                U32 const current2 = (U32)(ip-base);
    +                U32 const repIndex2 = current2 - offset_2;
    +                const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
    +                if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex))  /* intentional overflow */
    +                   && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
    +                    const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
    +                    size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
    +                    U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */
    +                    ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
    +                    hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
    +                    hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
    +                    ip += repLength2;
    +                    anchor = ip;
    +                    continue;
    +                }
    +                break;
    +    }   }   }
    +
    +    /* save reps for next block */
    +    seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
    +
    +    /* Last Literals */
    +    {   size_t const lastLLSize = iend - anchor;
    +        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    +        seqStorePtr->lit += lastLLSize;
    +    }
    +}
    +
    +
    +void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
    +                         const void* src, size_t srcSize)
    +{
    +    U32 const mls = ctx->appliedParams.cParams.searchLength;
    +    switch(mls)
    +    {
    +    default: /* includes case 3 */
    +    case 4 :
    +        ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
    +    case 5 :
    +        ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
    +    case 6 :
    +        ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
    +    case 7 :
    +        ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
    +    }
    +}
    diff --git a/lib/compress/zstd_double_fast.h b/lib/compress/zstd_double_fast.h
    new file mode 100644
    index 000000000..64f8bfef6
    --- /dev/null
    +++ b/lib/compress/zstd_double_fast.h
    @@ -0,0 +1,27 @@
    +/*
    + * 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).
    + */
    +
    +#ifndef ZSTD_DOUBLE_FAST_H
    +#define ZSTD_DOUBLE_FAST_H
    +
    +#include "zstd_compress.h"
    +
    +#if defined (__cplusplus)
    +extern "C" {
    +#endif
    +
    +void ZSTD_fillDoubleHashTable(ZSTD_CCtx* cctx, const void* end, const U32 mls);
    +void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
    +void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
    +
    +#if defined (__cplusplus)
    +}
    +#endif
    +
    +#endif /* ZSTD_DOUBLE_FAST_H */
    diff --git a/lib/compress/zstd_fast.c b/lib/compress/zstd_fast.c
    new file mode 100644
    index 000000000..82ab15a4c
    --- /dev/null
    +++ b/lib/compress/zstd_fast.c
    @@ -0,0 +1,247 @@
    +/*
    + * 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).
    + */
    +
    +#include "zstd_fast.h"
    +
    +
    +void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
    +{
    +    U32* const hashTable = zc->hashTable;
    +    U32  const hBits = zc->appliedParams.cParams.hashLog;
    +    const BYTE* const base = zc->base;
    +    const BYTE* ip = base + zc->nextToUpdate;
    +    const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
    +    const size_t fastHashFillStep = 3;
    +
    +    while(ip <= iend) {
    +        hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
    +        ip += fastHashFillStep;
    +    }
    +}
    +
    +
    +FORCE_INLINE_TEMPLATE
    +void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
    +                               const void* src, size_t srcSize,
    +                               const U32 mls)
    +{
    +    U32* const hashTable = cctx->hashTable;
    +    U32  const hBits = cctx->appliedParams.cParams.hashLog;
    +    seqStore_t* seqStorePtr = &(cctx->seqStore);
    +    const BYTE* const base = cctx->base;
    +    const BYTE* const istart = (const BYTE*)src;
    +    const BYTE* ip = istart;
    +    const BYTE* anchor = istart;
    +    const U32   lowestIndex = cctx->dictLimit;
    +    const BYTE* const lowest = base + lowestIndex;
    +    const BYTE* const iend = istart + srcSize;
    +    const BYTE* const ilimit = iend - HASH_READ_SIZE;
    +    U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
    +    U32 offsetSaved = 0;
    +
    +    /* init */
    +    ip += (ip==lowest);
    +    {   U32 const maxRep = (U32)(ip-lowest);
    +        if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
    +        if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
    +    }
    +
    +    /* Main Search Loop */
    +    while (ip < ilimit) {   /* < instead of <=, because repcode check at (ip+1) */
    +        size_t mLength;
    +        size_t const h = ZSTD_hashPtr(ip, hBits, mls);
    +        U32 const current = (U32)(ip-base);
    +        U32 const matchIndex = hashTable[h];
    +        const BYTE* match = base + matchIndex;
    +        hashTable[h] = current;   /* update hash table */
    +
    +        if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
    +            mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
    +            ip++;
    +            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
    +        } else {
    +            U32 offset;
    +            if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
    +                ip += ((ip-anchor) >> g_searchStrength) + 1;
    +                continue;
    +            }
    +            mLength = ZSTD_count(ip+4, match+4, iend) + 4;
    +            offset = (U32)(ip-match);
    +            while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
    +            offset_2 = offset_1;
    +            offset_1 = offset;
    +
    +            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
    +        }
    +
    +        /* match found */
    +        ip += mLength;
    +        anchor = ip;
    +
    +        if (ip <= ilimit) {
    +            /* Fill Table */
    +            hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;  /* here because current+2 could be > iend-8 */
    +            hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
    +            /* check immediate repcode */
    +            while ( (ip <= ilimit)
    +                 && ( (offset_2>0)
    +                 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
    +                /* store sequence */
    +                size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
    +                { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; }  /* swap offset_2 <=> offset_1 */
    +                hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
    +                ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
    +                ip += rLength;
    +                anchor = ip;
    +                continue;   /* faster when present ... (?) */
    +    }   }   }
    +
    +    /* save reps for next block */
    +    seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
    +    seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
    +
    +    /* Last Literals */
    +    {   size_t const lastLLSize = iend - anchor;
    +        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    +        seqStorePtr->lit += lastLLSize;
    +    }
    +}
    +
    +
    +void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
    +                       const void* src, size_t srcSize)
    +{
    +    const U32 mls = ctx->appliedParams.cParams.searchLength;
    +    switch(mls)
    +    {
    +    default: /* includes case 3 */
    +    case 4 :
    +        ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
    +    case 5 :
    +        ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
    +    case 6 :
    +        ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
    +    case 7 :
    +        ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
    +    }
    +}
    +
    +
    +static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
    +                                 const void* src, size_t srcSize,
    +                                 const U32 mls)
    +{
    +    U32* hashTable = ctx->hashTable;
    +    const U32 hBits = ctx->appliedParams.cParams.hashLog;
    +    seqStore_t* seqStorePtr = &(ctx->seqStore);
    +    const BYTE* const base = ctx->base;
    +    const BYTE* const dictBase = ctx->dictBase;
    +    const BYTE* const istart = (const BYTE*)src;
    +    const BYTE* ip = istart;
    +    const BYTE* anchor = istart;
    +    const U32   lowestIndex = ctx->lowLimit;
    +    const BYTE* const dictStart = dictBase + lowestIndex;
    +    const U32   dictLimit = ctx->dictLimit;
    +    const BYTE* const lowPrefixPtr = base + dictLimit;
    +    const BYTE* const dictEnd = dictBase + dictLimit;
    +    const BYTE* const iend = istart + srcSize;
    +    const BYTE* const ilimit = iend - 8;
    +    U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
    +
    +    /* Search Loop */
    +    while (ip < ilimit) {  /* < instead of <=, because (ip+1) */
    +        const size_t h = ZSTD_hashPtr(ip, hBits, mls);
    +        const U32 matchIndex = hashTable[h];
    +        const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
    +        const BYTE* match = matchBase + matchIndex;
    +        const U32 current = (U32)(ip-base);
    +        const U32 repIndex = current + 1 - offset_1;   /* offset_1 expected <= current +1 */
    +        const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
    +        const BYTE* repMatch = repBase + repIndex;
    +        size_t mLength;
    +        hashTable[h] = current;   /* update hash table */
    +
    +        if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
    +           && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
    +            const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
    +            mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
    +            ip++;
    +            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
    +        } else {
    +            if ( (matchIndex < lowestIndex) ||
    +                 (MEM_read32(match) != MEM_read32(ip)) ) {
    +                ip += ((ip-anchor) >> g_searchStrength) + 1;
    +                continue;
    +            }
    +            {   const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
    +                const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
    +                U32 offset;
    +                mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
    +                while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; }   /* catch up */
    +                offset = current - matchIndex;
    +                offset_2 = offset_1;
    +                offset_1 = offset;
    +                ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
    +        }   }
    +
    +        /* found a match : store it */
    +        ip += mLength;
    +        anchor = ip;
    +
    +        if (ip <= ilimit) {
    +            /* Fill Table */
    +            hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
    +            hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
    +            /* check immediate repcode */
    +            while (ip <= ilimit) {
    +                U32 const current2 = (U32)(ip-base);
    +                U32 const repIndex2 = current2 - offset_2;
    +                const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
    +                if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex))  /* intentional overflow */
    +                   && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
    +                    const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
    +                    size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
    +                    U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */
    +                    ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
    +                    hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
    +                    ip += repLength2;
    +                    anchor = ip;
    +                    continue;
    +                }
    +                break;
    +    }   }   }
    +
    +    /* save reps for next block */
    +    seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
    +
    +    /* Last Literals */
    +    {   size_t const lastLLSize = iend - anchor;
    +        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    +        seqStorePtr->lit += lastLLSize;
    +    }
    +}
    +
    +
    +void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
    +                         const void* src, size_t srcSize)
    +{
    +    U32 const mls = ctx->appliedParams.cParams.searchLength;
    +    switch(mls)
    +    {
    +    default: /* includes case 3 */
    +    case 4 :
    +        ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
    +    case 5 :
    +        ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
    +    case 6 :
    +        ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
    +    case 7 :
    +        ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
    +    }
    +}
    diff --git a/lib/compress/zstd_fast.h b/lib/compress/zstd_fast.h
    new file mode 100644
    index 000000000..f18b4617e
    --- /dev/null
    +++ b/lib/compress/zstd_fast.h
    @@ -0,0 +1,29 @@
    +/*
    + * 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).
    + */
    +
    +#ifndef ZSTD_FAST_H
    +#define ZSTD_FAST_H
    +
    +#include "zstd_compress.h"
    +
    +#if defined (__cplusplus)
    +extern "C" {
    +#endif
    +
    +void ZSTD_fillHashTable(ZSTD_CCtx* zc, const void* end, const U32 mls);
    +void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
    +                       const void* src, size_t srcSize);
    +void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
    +                         const void* src, size_t srcSize);
    +
    +#if defined (__cplusplus)
    +}
    +#endif
    +
    +#endif /* ZSTD_FAST_H */
    diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c
    new file mode 100644
    index 000000000..00ec1e286
    --- /dev/null
    +++ b/lib/compress/zstd_lazy.c
    @@ -0,0 +1,752 @@
    +/*
    + * 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).
    + */
    +
    +#include "zstd_lazy.h"
    +
    +
    +/*-*************************************
    +*  Binary Tree search
    +***************************************/
    +/** ZSTD_insertBt1() : add one or multiple positions to tree.
    +*   ip : assumed <= iend-8 .
    +*   @return : nb of positions added */
    +static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
    +                          U32 extDict)
    +{
    +    U32*   const hashTable = zc->hashTable;
    +    U32    const hashLog = zc->appliedParams.cParams.hashLog;
    +    size_t const h  = ZSTD_hashPtr(ip, hashLog, mls);
    +    U32*   const bt = zc->chainTable;
    +    U32    const btLog  = zc->appliedParams.cParams.chainLog - 1;
    +    U32    const btMask = (1 << btLog) - 1;
    +    U32 matchIndex = hashTable[h];
    +    size_t commonLengthSmaller=0, commonLengthLarger=0;
    +    const BYTE* const base = zc->base;
    +    const BYTE* const dictBase = zc->dictBase;
    +    const U32 dictLimit = zc->dictLimit;
    +    const BYTE* const dictEnd = dictBase + dictLimit;
    +    const BYTE* const prefixStart = base + dictLimit;
    +    const BYTE* match;
    +    const U32 current = (U32)(ip-base);
    +    const U32 btLow = btMask >= current ? 0 : current - btMask;
    +    U32* smallerPtr = bt + 2*(current&btMask);
    +    U32* largerPtr  = smallerPtr + 1;
    +    U32 dummy32;   /* to be nullified at the end */
    +    U32 const windowLow = zc->lowLimit;
    +    U32 matchEndIdx = current+8;
    +    size_t bestLength = 8;
    +#ifdef ZSTD_C_PREDICT
    +    U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
    +    U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
    +    predictedSmall += (predictedSmall>0);
    +    predictedLarge += (predictedLarge>0);
    +#endif /* ZSTD_C_PREDICT */
    +
    +    hashTable[h] = current;   /* Update Hash Table */
    +
    +    while (nbCompares-- && (matchIndex > windowLow)) {
    +        U32* const nextPtr = bt + 2*(matchIndex & btMask);
    +        size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
    +
    +#ifdef ZSTD_C_PREDICT   /* note : can create issues when hlog small <= 11 */
    +        const U32* predictPtr = bt + 2*((matchIndex-1) & btMask);   /* written this way, as bt is a roll buffer */
    +        if (matchIndex == predictedSmall) {
    +            /* no need to check length, result known */
    +            *smallerPtr = matchIndex;
    +            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    +            smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */
    +            matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
    +            predictedSmall = predictPtr[1] + (predictPtr[1]>0);
    +            continue;
    +        }
    +        if (matchIndex == predictedLarge) {
    +            *largerPtr = matchIndex;
    +            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    +            largerPtr = nextPtr;
    +            matchIndex = nextPtr[0];
    +            predictedLarge = predictPtr[0] + (predictPtr[0]>0);
    +            continue;
    +        }
    +#endif
    +        if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
    +            match = base + matchIndex;
    +            if (match[matchLength] == ip[matchLength])
    +                matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
    +        } else {
    +            match = dictBase + matchIndex;
    +            matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
    +            if (matchIndex+matchLength >= dictLimit)
    +                match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */
    +        }
    +
    +        if (matchLength > bestLength) {
    +            bestLength = matchLength;
    +            if (matchLength > matchEndIdx - matchIndex)
    +                matchEndIdx = matchIndex + (U32)matchLength;
    +        }
    +
    +        if (ip+matchLength == iend)   /* equal : no way to know if inf or sup */
    +            break;   /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
    +
    +        if (match[matchLength] < ip[matchLength]) {  /* necessarily within correct buffer */
    +            /* match is smaller than current */
    +            *smallerPtr = matchIndex;             /* update smaller idx */
    +            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
    +            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    +            smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */
    +            matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
    +        } else {
    +            /* match is larger than current */
    +            *largerPtr = matchIndex;
    +            commonLengthLarger = matchLength;
    +            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    +            largerPtr = nextPtr;
    +            matchIndex = nextPtr[0];
    +    }   }
    +
    +    *smallerPtr = *largerPtr = 0;
    +    if (bestLength > 384) return MIN(192, (U32)(bestLength - 384));   /* speed optimization */
    +    if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
    +    return 1;
    +}
    +
    +
    +static size_t ZSTD_insertBtAndFindBestMatch (
    +                        ZSTD_CCtx* zc,
    +                        const BYTE* const ip, const BYTE* const iend,
    +                        size_t* offsetPtr,
    +                        U32 nbCompares, const U32 mls,
    +                        U32 extDict)
    +{
    +    U32*   const hashTable = zc->hashTable;
    +    U32    const hashLog = zc->appliedParams.cParams.hashLog;
    +    size_t const h  = ZSTD_hashPtr(ip, hashLog, mls);
    +    U32*   const bt = zc->chainTable;
    +    U32    const btLog  = zc->appliedParams.cParams.chainLog - 1;
    +    U32    const btMask = (1 << btLog) - 1;
    +    U32 matchIndex  = hashTable[h];
    +    size_t commonLengthSmaller=0, commonLengthLarger=0;
    +    const BYTE* const base = zc->base;
    +    const BYTE* const dictBase = zc->dictBase;
    +    const U32 dictLimit = zc->dictLimit;
    +    const BYTE* const dictEnd = dictBase + dictLimit;
    +    const BYTE* const prefixStart = base + dictLimit;
    +    const U32 current = (U32)(ip-base);
    +    const U32 btLow = btMask >= current ? 0 : current - btMask;
    +    const U32 windowLow = zc->lowLimit;
    +    U32* smallerPtr = bt + 2*(current&btMask);
    +    U32* largerPtr  = bt + 2*(current&btMask) + 1;
    +    U32 matchEndIdx = current+8;
    +    U32 dummy32;   /* to be nullified at the end */
    +    size_t bestLength = 0;
    +
    +    hashTable[h] = current;   /* Update Hash Table */
    +
    +    while (nbCompares-- && (matchIndex > windowLow)) {
    +        U32* const nextPtr = bt + 2*(matchIndex & btMask);
    +        size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
    +        const BYTE* match;
    +
    +        if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
    +            match = base + matchIndex;
    +            if (match[matchLength] == ip[matchLength])
    +                matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
    +        } else {
    +            match = dictBase + matchIndex;
    +            matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
    +            if (matchIndex+matchLength >= dictLimit)
    +                match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */
    +        }
    +
    +        if (matchLength > bestLength) {
    +            if (matchLength > matchEndIdx - matchIndex)
    +                matchEndIdx = matchIndex + (U32)matchLength;
    +            if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
    +                bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
    +            if (ip+matchLength == iend)   /* equal : no way to know if inf or sup */
    +                break;   /* drop, to guarantee consistency (miss a little bit of compression) */
    +        }
    +
    +        if (match[matchLength] < ip[matchLength]) {
    +            /* match is smaller than current */
    +            *smallerPtr = matchIndex;             /* update smaller idx */
    +            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
    +            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    +            smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */
    +            matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
    +        } else {
    +            /* match is larger than current */
    +            *largerPtr = matchIndex;
    +            commonLengthLarger = matchLength;
    +            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    +            largerPtr = nextPtr;
    +            matchIndex = nextPtr[0];
    +    }   }
    +
    +    *smallerPtr = *largerPtr = 0;
    +
    +    zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
    +    return bestLength;
    +}
    +
    +
    +void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
    +{
    +    const BYTE* const base = zc->base;
    +    const U32 target = (U32)(ip - base);
    +    U32 idx = zc->nextToUpdate;
    +
    +    while(idx < target)
    +        idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
    +}
    +
    +/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
    +static size_t ZSTD_BtFindBestMatch (
    +                        ZSTD_CCtx* zc,
    +                        const BYTE* const ip, const BYTE* const iLimit,
    +                        size_t* offsetPtr,
    +                        const U32 maxNbAttempts, const U32 mls)
    +{
    +    if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */
    +    ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
    +    return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
    +}
    +
    +
    +static size_t ZSTD_BtFindBestMatch_selectMLS (
    +                        ZSTD_CCtx* zc,   /* Index table will be updated */
    +                        const BYTE* ip, const BYTE* const iLimit,
    +                        size_t* offsetPtr,
    +                        const U32 maxNbAttempts, const U32 matchLengthSearch)
    +{
    +    switch(matchLengthSearch)
    +    {
    +    default : /* includes case 3 */
    +    case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
    +    case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
    +    case 7 :
    +    case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
    +    }
    +}
    +
    +
    +void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
    +{
    +    const BYTE* const base = zc->base;
    +    const U32 target = (U32)(ip - base);
    +    U32 idx = zc->nextToUpdate;
    +
    +    while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
    +}
    +
    +
    +/** Tree updater, providing best match */
    +static size_t ZSTD_BtFindBestMatch_extDict (
    +                        ZSTD_CCtx* zc,
    +                        const BYTE* const ip, const BYTE* const iLimit,
    +                        size_t* offsetPtr,
    +                        const U32 maxNbAttempts, const U32 mls)
    +{
    +    if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */
    +    ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
    +    return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
    +}
    +
    +
    +static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
    +                        ZSTD_CCtx* zc,   /* Index table will be updated */
    +                        const BYTE* ip, const BYTE* const iLimit,
    +                        size_t* offsetPtr,
    +                        const U32 maxNbAttempts, const U32 matchLengthSearch)
    +{
    +    switch(matchLengthSearch)
    +    {
    +    default : /* includes case 3 */
    +    case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
    +    case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
    +    case 7 :
    +    case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
    +    }
    +}
    +
    +
    +
    +/* *********************************
    +*  Hash Chain
    +***********************************/
    +#define NEXT_IN_CHAIN(d, mask)   chainTable[(d) & mask]
    +
    +/* Update chains up to ip (excluded)
    +   Assumption : always within prefix (i.e. not within extDict) */
    +U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
    +{
    +    U32* const hashTable  = zc->hashTable;
    +    const U32 hashLog = zc->appliedParams.cParams.hashLog;
    +    U32* const chainTable = zc->chainTable;
    +    const U32 chainMask = (1 << zc->appliedParams.cParams.chainLog) - 1;
    +    const BYTE* const base = zc->base;
    +    const U32 target = (U32)(ip - base);
    +    U32 idx = zc->nextToUpdate;
    +
    +    while(idx < target) { /* catch up */
    +        size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
    +        NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
    +        hashTable[h] = idx;
    +        idx++;
    +    }
    +
    +    zc->nextToUpdate = target;
    +    return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
    +}
    +
    +
    +/* inlining is important to hardwire a hot branch (template emulation) */
    +FORCE_INLINE_TEMPLATE
    +size_t ZSTD_HcFindBestMatch_generic (
    +                        ZSTD_CCtx* zc,   /* Index table will be updated */
    +                        const BYTE* const ip, const BYTE* const iLimit,
    +                        size_t* offsetPtr,
    +                        const U32 maxNbAttempts, const U32 mls, const U32 extDict)
    +{
    +    U32* const chainTable = zc->chainTable;
    +    const U32 chainSize = (1 << zc->appliedParams.cParams.chainLog);
    +    const U32 chainMask = chainSize-1;
    +    const BYTE* const base = zc->base;
    +    const BYTE* const dictBase = zc->dictBase;
    +    const U32 dictLimit = zc->dictLimit;
    +    const BYTE* const prefixStart = base + dictLimit;
    +    const BYTE* const dictEnd = dictBase + dictLimit;
    +    const U32 lowLimit = zc->lowLimit;
    +    const U32 current = (U32)(ip-base);
    +    const U32 minChain = current > chainSize ? current - chainSize : 0;
    +    int nbAttempts=maxNbAttempts;
    +    size_t ml=4-1;
    +
    +    /* HC4 match finder */
    +    U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
    +
    +    for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
    +        const BYTE* match;
    +        size_t currentMl=0;
    +        if ((!extDict) || matchIndex >= dictLimit) {
    +            match = base + matchIndex;
    +            if (match[ml] == ip[ml])   /* potentially better */
    +                currentMl = ZSTD_count(ip, match, iLimit);
    +        } else {
    +            match = dictBase + matchIndex;
    +            if (MEM_read32(match) == MEM_read32(ip))   /* assumption : matchIndex <= dictLimit-4 (by table construction) */
    +                currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
    +        }
    +
    +        /* save best solution */
    +        if (currentMl > ml) {
    +            ml = currentMl;
    +            *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
    +            if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
    +        }
    +
    +        if (matchIndex <= minChain) break;
    +        matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
    +    }
    +
    +    return ml;
    +}
    +
    +
    +FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
    +                        ZSTD_CCtx* zc,
    +                        const BYTE* ip, const BYTE* const iLimit,
    +                        size_t* offsetPtr,
    +                        const U32 maxNbAttempts, const U32 matchLengthSearch)
    +{
    +    switch(matchLengthSearch)
    +    {
    +    default : /* includes case 3 */
    +    case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
    +    case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
    +    case 7 :
    +    case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
    +    }
    +}
    +
    +
    +FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
    +                        ZSTD_CCtx* zc,
    +                        const BYTE* ip, const BYTE* const iLimit,
    +                        size_t* offsetPtr,
    +                        const U32 maxNbAttempts, const U32 matchLengthSearch)
    +{
    +    switch(matchLengthSearch)
    +    {
    +    default : /* includes case 3 */
    +    case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
    +    case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
    +    case 7 :
    +    case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
    +    }
    +}
    +
    +
    +/* *******************************
    +*  Common parser - lazy strategy
    +*********************************/
    +FORCE_INLINE_TEMPLATE
    +void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
    +                                     const void* src, size_t srcSize,
    +                                     const U32 searchMethod, const U32 depth)
    +{
    +    seqStore_t* seqStorePtr = &(ctx->seqStore);
    +    const BYTE* const istart = (const BYTE*)src;
    +    const BYTE* ip = istart;
    +    const BYTE* anchor = istart;
    +    const BYTE* const iend = istart + srcSize;
    +    const BYTE* const ilimit = iend - 8;
    +    const BYTE* const base = ctx->base + ctx->dictLimit;
    +
    +    U32 const maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
    +    U32 const mls = ctx->appliedParams.cParams.searchLength;
    +
    +    typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
    +                        size_t* offsetPtr,
    +                        U32 maxNbAttempts, U32 matchLengthSearch);
    +    searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
    +    U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1], savedOffset=0;
    +
    +    /* init */
    +    ip += (ip==base);
    +    ctx->nextToUpdate3 = ctx->nextToUpdate;
    +    {   U32 const maxRep = (U32)(ip-base);
    +        if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
    +        if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
    +    }
    +
    +    /* Match Loop */
    +    while (ip < ilimit) {
    +        size_t matchLength=0;
    +        size_t offset=0;
    +        const BYTE* start=ip+1;
    +
    +        /* check repCode */
    +        if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
    +            /* repcode : we take it */
    +            matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
    +            if (depth==0) goto _storeSequence;
    +        }
    +
    +        /* first search (depth 0) */
    +        {   size_t offsetFound = 99999999;
    +            size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
    +            if (ml2 > matchLength)
    +                matchLength = ml2, start = ip, offset=offsetFound;
    +        }
    +
    +        if (matchLength < 4) {
    +            ip += ((ip-anchor) >> g_searchStrength) + 1;   /* jump faster over incompressible sections */
    +            continue;
    +        }
    +
    +        /* let's try to find a better solution */
    +        if (depth>=1)
    +        while (ip0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
    +                size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
    +                int const gain2 = (int)(mlRep * 3);
    +                int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
    +                if ((mlRep >= 4) && (gain2 > gain1))
    +                    matchLength = mlRep, offset = 0, start = ip;
    +            }
    +            {   size_t offset2=99999999;
    +                size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
    +                int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */
    +                int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
    +                if ((ml2 >= 4) && (gain2 > gain1)) {
    +                    matchLength = ml2, offset = offset2, start = ip;
    +                    continue;   /* search a better one */
    +            }   }
    +
    +            /* let's find an even better one */
    +            if ((depth==2) && (ip0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
    +                    size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
    +                    int const gain2 = (int)(ml2 * 4);
    +                    int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
    +                    if ((ml2 >= 4) && (gain2 > gain1))
    +                        matchLength = ml2, offset = 0, start = ip;
    +                }
    +                {   size_t offset2=99999999;
    +                    size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
    +                    int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */
    +                    int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
    +                    if ((ml2 >= 4) && (gain2 > gain1)) {
    +                        matchLength = ml2, offset = offset2, start = ip;
    +                        continue;
    +            }   }   }
    +            break;  /* nothing found : store previous solution */
    +        }
    +
    +        /* NOTE:
    +         * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior.
    +         * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which
    +         * overflows the pointer, which is undefined behavior.
    +         */
    +        /* catch up */
    +        if (offset) {
    +            while ( (start > anchor)
    +                 && (start > base+offset-ZSTD_REP_MOVE)
    +                 && (start[-1] == (start-offset+ZSTD_REP_MOVE)[-1]) )  /* only search for offset within prefix */
    +                { start--; matchLength++; }
    +            offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
    +        }
    +        /* store sequence */
    +_storeSequence:
    +        {   size_t const litLength = start - anchor;
    +            ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
    +            anchor = ip = start + matchLength;
    +        }
    +
    +        /* check immediate repcode */
    +        while ( (ip <= ilimit)
    +             && ((offset_2>0)
    +             & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
    +            /* store sequence */
    +            matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
    +            offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
    +            ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
    +            ip += matchLength;
    +            anchor = ip;
    +            continue;   /* faster when present ... (?) */
    +    }   }
    +
    +    /* Save reps for next block */
    +    seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
    +    seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
    +
    +    /* Last Literals */
    +    {   size_t const lastLLSize = iend - anchor;
    +        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    +        seqStorePtr->lit += lastLLSize;
    +    }
    +}
    +
    +
    +void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    +{
    +    ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
    +}
    +
    +void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    +{
    +    ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
    +}
    +
    +void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    +{
    +    ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
    +}
    +
    +void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    +{
    +    ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
    +}
    +
    +
    +FORCE_INLINE_TEMPLATE
    +void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
    +                                     const void* src, size_t srcSize,
    +                                     const U32 searchMethod, const U32 depth)
    +{
    +    seqStore_t* seqStorePtr = &(ctx->seqStore);
    +    const BYTE* const istart = (const BYTE*)src;
    +    const BYTE* ip = istart;
    +    const BYTE* anchor = istart;
    +    const BYTE* const iend = istart + srcSize;
    +    const BYTE* const ilimit = iend - 8;
    +    const BYTE* const base = ctx->base;
    +    const U32 dictLimit = ctx->dictLimit;
    +    const U32 lowestIndex = ctx->lowLimit;
    +    const BYTE* const prefixStart = base + dictLimit;
    +    const BYTE* const dictBase = ctx->dictBase;
    +    const BYTE* const dictEnd  = dictBase + dictLimit;
    +    const BYTE* const dictStart  = dictBase + ctx->lowLimit;
    +
    +    const U32 maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
    +    const U32 mls = ctx->appliedParams.cParams.searchLength;
    +
    +    typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
    +                        size_t* offsetPtr,
    +                        U32 maxNbAttempts, U32 matchLengthSearch);
    +    searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
    +
    +    U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1];
    +
    +    /* init */
    +    ctx->nextToUpdate3 = ctx->nextToUpdate;
    +    ip += (ip == prefixStart);
    +
    +    /* Match Loop */
    +    while (ip < ilimit) {
    +        size_t matchLength=0;
    +        size_t offset=0;
    +        const BYTE* start=ip+1;
    +        U32 current = (U32)(ip-base);
    +
    +        /* check repCode */
    +        {   const U32 repIndex = (U32)(current+1 - offset_1);
    +            const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
    +            const BYTE* const repMatch = repBase + repIndex;
    +            if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))   /* intentional overflow */
    +            if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
    +                /* repcode detected we should take it */
    +                const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
    +                matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
    +                if (depth==0) goto _storeSequence;
    +        }   }
    +
    +        /* first search (depth 0) */
    +        {   size_t offsetFound = 99999999;
    +            size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
    +            if (ml2 > matchLength)
    +                matchLength = ml2, start = ip, offset=offsetFound;
    +        }
    +
    +         if (matchLength < 4) {
    +            ip += ((ip-anchor) >> g_searchStrength) + 1;   /* jump faster over incompressible sections */
    +            continue;
    +        }
    +
    +        /* let's try to find a better solution */
    +        if (depth>=1)
    +        while (ip= 3) & (repIndex > lowestIndex))  /* intentional overflow */
    +                if (MEM_read32(ip) == MEM_read32(repMatch)) {
    +                    /* repcode detected */
    +                    const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
    +                    size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
    +                    int const gain2 = (int)(repLength * 3);
    +                    int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
    +                    if ((repLength >= 4) && (gain2 > gain1))
    +                        matchLength = repLength, offset = 0, start = ip;
    +            }   }
    +
    +            /* search match, depth 1 */
    +            {   size_t offset2=99999999;
    +                size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
    +                int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */
    +                int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
    +                if ((ml2 >= 4) && (gain2 > gain1)) {
    +                    matchLength = ml2, offset = offset2, start = ip;
    +                    continue;   /* search a better one */
    +            }   }
    +
    +            /* let's find an even better one */
    +            if ((depth==2) && (ip= 3) & (repIndex > lowestIndex))  /* intentional overflow */
    +                    if (MEM_read32(ip) == MEM_read32(repMatch)) {
    +                        /* repcode detected */
    +                        const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
    +                        size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
    +                        int const gain2 = (int)(repLength * 4);
    +                        int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
    +                        if ((repLength >= 4) && (gain2 > gain1))
    +                            matchLength = repLength, offset = 0, start = ip;
    +                }   }
    +
    +                /* search match, depth 2 */
    +                {   size_t offset2=99999999;
    +                    size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
    +                    int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */
    +                    int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
    +                    if ((ml2 >= 4) && (gain2 > gain1)) {
    +                        matchLength = ml2, offset = offset2, start = ip;
    +                        continue;
    +            }   }   }
    +            break;  /* nothing found : store previous solution */
    +        }
    +
    +        /* catch up */
    +        if (offset) {
    +            U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
    +            const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
    +            const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
    +            while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; }  /* catch up */
    +            offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
    +        }
    +
    +        /* store sequence */
    +_storeSequence:
    +        {   size_t const litLength = start - anchor;
    +            ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
    +            anchor = ip = start + matchLength;
    +        }
    +
    +        /* check immediate repcode */
    +        while (ip <= ilimit) {
    +            const U32 repIndex = (U32)((ip-base) - offset_2);
    +            const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
    +            const BYTE* const repMatch = repBase + repIndex;
    +            if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))  /* intentional overflow */
    +            if (MEM_read32(ip) == MEM_read32(repMatch)) {
    +                /* repcode detected we should take it */
    +                const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
    +                matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
    +                offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset;   /* swap offset history */
    +                ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
    +                ip += matchLength;
    +                anchor = ip;
    +                continue;   /* faster when present ... (?) */
    +            }
    +            break;
    +    }   }
    +
    +    /* Save reps for next block */
    +    seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
    +
    +    /* Last Literals */
    +    {   size_t const lastLLSize = iend - anchor;
    +        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    +        seqStorePtr->lit += lastLLSize;
    +    }
    +}
    +
    +
    +void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    +{
    +    ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
    +}
    +
    +void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    +{
    +    ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
    +}
    +
    +void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    +{
    +    ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
    +}
    +
    +void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    +{
    +    ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
    +}
    diff --git a/lib/compress/zstd_lazy.h b/lib/compress/zstd_lazy.h
    new file mode 100644
    index 000000000..451cddf96
    --- /dev/null
    +++ b/lib/compress/zstd_lazy.h
    @@ -0,0 +1,37 @@
    +/*
    + * 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).
    + */
    +
    +#ifndef ZSTD_LAZY_H
    +#define ZSTD_LAZY_H
    +
    +#include "zstd_compress.h"
    +
    +#if defined (__cplusplus)
    +extern "C" {
    +#endif
    +
    +U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls);
    +void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls);
    +void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls);
    +
    +void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
    +void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
    +void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
    +void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
    +
    +void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
    +void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
    +void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
    +void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
    +
    +#if defined (__cplusplus)
    +}
    +#endif
    +
    +#endif /* ZSTD_LAZY_H */
    diff --git a/lib/compress/zstd_opt.c b/lib/compress/zstd_opt.c
    new file mode 100644
    index 000000000..03e945516
    --- /dev/null
    +++ b/lib/compress/zstd_opt.c
    @@ -0,0 +1,954 @@
    +/*
    + * Copyright (c) 2016-present, Przemyslaw Skibinski, 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).
    + */
    +
    +#include "zstd_opt.h"
    +#include "zstd_lazy.h"
    +
    +
    +#define ZSTD_LITFREQ_ADD    2
    +#define ZSTD_FREQ_DIV       4
    +#define ZSTD_MAX_PRICE      (1<<30)
    +
    +/*-*************************************
    +*  Price functions for optimal parser
    +***************************************/
    +static void ZSTD_setLog2Prices(optState_t* optPtr)
    +{
    +    optPtr->log2matchLengthSum = ZSTD_highbit32(optPtr->matchLengthSum+1);
    +    optPtr->log2litLengthSum = ZSTD_highbit32(optPtr->litLengthSum+1);
    +    optPtr->log2litSum = ZSTD_highbit32(optPtr->litSum+1);
    +    optPtr->log2offCodeSum = ZSTD_highbit32(optPtr->offCodeSum+1);
    +    optPtr->factor = 1 + ((optPtr->litSum>>5) / optPtr->litLengthSum) + ((optPtr->litSum<<1) / (optPtr->litSum + optPtr->matchSum));
    +}
    +
    +
    +static void ZSTD_rescaleFreqs(optState_t* optPtr, const BYTE* src, size_t srcSize)
    +{
    +    unsigned u;
    +
    +    optPtr->cachedLiterals = NULL;
    +    optPtr->cachedPrice = optPtr->cachedLitLength = 0;
    +    optPtr->staticPrices = 0;
    +
    +    if (optPtr->litLengthSum == 0) {
    +        if (srcSize <= 1024) optPtr->staticPrices = 1;
    +
    +        assert(optPtr->litFreq!=NULL);
    +        for (u=0; u<=MaxLit; u++)
    +            optPtr->litFreq[u] = 0;
    +        for (u=0; ulitFreq[src[u]]++;
    +
    +        optPtr->litSum = 0;
    +        optPtr->litLengthSum = MaxLL+1;
    +        optPtr->matchLengthSum = MaxML+1;
    +        optPtr->offCodeSum = (MaxOff+1);
    +        optPtr->matchSum = (ZSTD_LITFREQ_ADD<litFreq[u] = 1 + (optPtr->litFreq[u]>>ZSTD_FREQ_DIV);
    +            optPtr->litSum += optPtr->litFreq[u];
    +        }
    +        for (u=0; u<=MaxLL; u++)
    +            optPtr->litLengthFreq[u] = 1;
    +        for (u=0; u<=MaxML; u++)
    +            optPtr->matchLengthFreq[u] = 1;
    +        for (u=0; u<=MaxOff; u++)
    +            optPtr->offCodeFreq[u] = 1;
    +    } else {
    +        optPtr->matchLengthSum = 0;
    +        optPtr->litLengthSum = 0;
    +        optPtr->offCodeSum = 0;
    +        optPtr->matchSum = 0;
    +        optPtr->litSum = 0;
    +
    +        for (u=0; u<=MaxLit; u++) {
    +            optPtr->litFreq[u] = 1 + (optPtr->litFreq[u]>>(ZSTD_FREQ_DIV+1));
    +            optPtr->litSum += optPtr->litFreq[u];
    +        }
    +        for (u=0; u<=MaxLL; u++) {
    +            optPtr->litLengthFreq[u] = 1 + (optPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1));
    +            optPtr->litLengthSum += optPtr->litLengthFreq[u];
    +        }
    +        for (u=0; u<=MaxML; u++) {
    +            optPtr->matchLengthFreq[u] = 1 + (optPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV);
    +            optPtr->matchLengthSum += optPtr->matchLengthFreq[u];
    +            optPtr->matchSum += optPtr->matchLengthFreq[u] * (u + 3);
    +        }
    +        optPtr->matchSum *= ZSTD_LITFREQ_ADD;
    +        for (u=0; u<=MaxOff; u++) {
    +            optPtr->offCodeFreq[u] = 1 + (optPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV);
    +            optPtr->offCodeSum += optPtr->offCodeFreq[u];
    +        }
    +    }
    +
    +    ZSTD_setLog2Prices(optPtr);
    +}
    +
    +
    +static U32 ZSTD_getLiteralPrice(optState_t* optPtr, U32 litLength, const BYTE* literals)
    +{
    +    U32 price, u;
    +
    +    if (optPtr->staticPrices)
    +        return ZSTD_highbit32((U32)litLength+1) + (litLength*6);
    +
    +    if (litLength == 0)
    +        return optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[0]+1);
    +
    +    /* literals */
    +    if (optPtr->cachedLiterals == literals) {
    +        U32 const additional = litLength - optPtr->cachedLitLength;
    +        const BYTE* literals2 = optPtr->cachedLiterals + optPtr->cachedLitLength;
    +        price = optPtr->cachedPrice + additional * optPtr->log2litSum;
    +        for (u=0; u < additional; u++)
    +            price -= ZSTD_highbit32(optPtr->litFreq[literals2[u]]+1);
    +        optPtr->cachedPrice = price;
    +        optPtr->cachedLitLength = litLength;
    +    } else {
    +        price = litLength * optPtr->log2litSum;
    +        for (u=0; u < litLength; u++)
    +            price -= ZSTD_highbit32(optPtr->litFreq[literals[u]]+1);
    +
    +        if (litLength >= 12) {
    +            optPtr->cachedLiterals = literals;
    +            optPtr->cachedPrice = price;
    +            optPtr->cachedLitLength = litLength;
    +        }
    +    }
    +
    +    /* literal Length */
    +    {   const BYTE LL_deltaCode = 19;
    +        const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
    +        price += LL_bits[llCode] + optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1);
    +    }
    +
    +    return price;
    +}
    +
    +
    +FORCE_INLINE_TEMPLATE U32 ZSTD_getPrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength, const int ultra)
    +{
    +    /* offset */
    +    U32 price;
    +    BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
    +
    +    if (optPtr->staticPrices)
    +        return ZSTD_getLiteralPrice(optPtr, litLength, literals) + ZSTD_highbit32((U32)matchLength+1) + 16 + offCode;
    +
    +    price = offCode + optPtr->log2offCodeSum - ZSTD_highbit32(optPtr->offCodeFreq[offCode]+1);
    +    if (!ultra && offCode >= 20) price += (offCode-19)*2;
    +
    +    /* match Length */
    +    {   const BYTE ML_deltaCode = 36;
    +        const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
    +        price += ML_bits[mlCode] + optPtr->log2matchLengthSum - ZSTD_highbit32(optPtr->matchLengthFreq[mlCode]+1);
    +    }
    +
    +    return price + ZSTD_getLiteralPrice(optPtr, litLength, literals) + optPtr->factor;
    +}
    +
    +
    +static void ZSTD_updatePrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength)
    +{
    +    U32 u;
    +
    +    /* literals */
    +    optPtr->litSum += litLength*ZSTD_LITFREQ_ADD;
    +    for (u=0; u < litLength; u++)
    +        optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
    +
    +    /* literal Length */
    +    {   const BYTE LL_deltaCode = 19;
    +        const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
    +        optPtr->litLengthFreq[llCode]++;
    +        optPtr->litLengthSum++;
    +    }
    +
    +    /* match offset */
    +    {   BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
    +        optPtr->offCodeSum++;
    +        optPtr->offCodeFreq[offCode]++;
    +    }
    +
    +    /* match Length */
    +    {   const BYTE ML_deltaCode = 36;
    +        const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
    +        optPtr->matchLengthFreq[mlCode]++;
    +        optPtr->matchLengthSum++;
    +    }
    +
    +    ZSTD_setLog2Prices(optPtr);
    +}
    +
    +
    +#define SET_PRICE(pos, mlen_, offset_, litlen_, price_)   \
    +    {                                                 \
    +        while (last_pos < pos)  { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } \
    +        opt[pos].mlen = mlen_;                         \
    +        opt[pos].off = offset_;                        \
    +        opt[pos].litlen = litlen_;                     \
    +        opt[pos].price = price_;                       \
    +    }
    +
    +
    +/* function safe only for comparisons */
    +static U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
    +{
    +    switch (length)
    +    {
    +    default :
    +    case 4 : return MEM_read32(memPtr);
    +    case 3 : if (MEM_isLittleEndian())
    +                return MEM_read32(memPtr)<<8;
    +             else
    +                return MEM_read32(memPtr)>>8;
    +    }
    +}
    +
    +
    +/* Update hashTable3 up to ip (excluded)
    +   Assumption : always within prefix (i.e. not within extDict) */
    +static
    +U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* zc, const BYTE* ip)
    +{
    +    U32* const hashTable3  = zc->hashTable3;
    +    U32 const hashLog3  = zc->hashLog3;
    +    const BYTE* const base = zc->base;
    +    U32 idx = zc->nextToUpdate3;
    +    const U32 target = zc->nextToUpdate3 = (U32)(ip - base);
    +    const size_t hash3 = ZSTD_hash3Ptr(ip, hashLog3);
    +
    +    while(idx < target) {
    +        hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
    +        idx++;
    +    }
    +
    +    return hashTable3[hash3];
    +}
    +
    +
    +/*-*************************************
    +*  Binary Tree search
    +***************************************/
    +static U32 ZSTD_insertBtAndGetAllMatches (
    +                        ZSTD_CCtx* zc,
    +                        const BYTE* const ip, const BYTE* const iLimit,
    +                        U32 nbCompares, const U32 mls,
    +                        U32 extDict, ZSTD_match_t* matches, const U32 minMatchLen)
    +{
    +    const BYTE* const base = zc->base;
    +    const U32 current = (U32)(ip-base);
    +    const U32 hashLog = zc->appliedParams.cParams.hashLog;
    +    const size_t h  = ZSTD_hashPtr(ip, hashLog, mls);
    +    U32* const hashTable = zc->hashTable;
    +    U32 matchIndex  = hashTable[h];
    +    U32* const bt   = zc->chainTable;
    +    const U32 btLog = zc->appliedParams.cParams.chainLog - 1;
    +    const U32 btMask= (1U << btLog) - 1;
    +    size_t commonLengthSmaller=0, commonLengthLarger=0;
    +    const BYTE* const dictBase = zc->dictBase;
    +    const U32 dictLimit = zc->dictLimit;
    +    const BYTE* const dictEnd = dictBase + dictLimit;
    +    const BYTE* const prefixStart = base + dictLimit;
    +    const U32 btLow = btMask >= current ? 0 : current - btMask;
    +    const U32 windowLow = zc->lowLimit;
    +    U32* smallerPtr = bt + 2*(current&btMask);
    +    U32* largerPtr  = bt + 2*(current&btMask) + 1;
    +    U32 matchEndIdx = current+8;
    +    U32 dummy32;   /* to be nullified at the end */
    +    U32 mnum = 0;
    +
    +    const U32 minMatch = (mls == 3) ? 3 : 4;
    +    size_t bestLength = minMatchLen-1;
    +
    +    if (minMatch == 3) { /* HC3 match finder */
    +        U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip);
    +        if (matchIndex3>windowLow && (current - matchIndex3 < (1<<18))) {
    +            const BYTE* match;
    +            size_t currentMl=0;
    +            if ((!extDict) || matchIndex3 >= dictLimit) {
    +                match = base + matchIndex3;
    +                if (match[bestLength] == ip[bestLength]) currentMl = ZSTD_count(ip, match, iLimit);
    +            } else {
    +                match = dictBase + matchIndex3;
    +                if (ZSTD_readMINMATCH(match, MINMATCH) == ZSTD_readMINMATCH(ip, MINMATCH))    /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */
    +                    currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
    +            }
    +
    +            /* save best solution */
    +            if (currentMl > bestLength) {
    +                bestLength = currentMl;
    +                matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex3;
    +                matches[mnum].len = (U32)currentMl;
    +                mnum++;
    +                if (currentMl > ZSTD_OPT_NUM) goto update;
    +                if (ip+currentMl == iLimit) goto update; /* best possible, and avoid read overflow*/
    +            }
    +        }
    +    }
    +
    +    hashTable[h] = current;   /* Update Hash Table */
    +
    +    while (nbCompares-- && (matchIndex > windowLow)) {
    +        U32* nextPtr = bt + 2*(matchIndex & btMask);
    +        size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
    +        const BYTE* match;
    +
    +        if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
    +            match = base + matchIndex;
    +            if (match[matchLength] == ip[matchLength]) {
    +                matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iLimit) +1;
    +            }
    +        } else {
    +            match = dictBase + matchIndex;
    +            matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
    +            if (matchIndex+matchLength >= dictLimit)
    +                match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */
    +        }
    +
    +        if (matchLength > bestLength) {
    +            if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength;
    +            bestLength = matchLength;
    +            matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex;
    +            matches[mnum].len = (U32)matchLength;
    +            mnum++;
    +            if (matchLength > ZSTD_OPT_NUM) break;
    +            if (ip+matchLength == iLimit)   /* equal : no way to know if inf or sup */
    +                break;   /* drop, to guarantee consistency (miss a little bit of compression) */
    +        }
    +
    +        if (match[matchLength] < ip[matchLength]) {
    +            /* match is smaller than current */
    +            *smallerPtr = matchIndex;             /* update smaller idx */
    +            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
    +            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    +            smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */
    +            matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
    +        } else {
    +            /* match is larger than current */
    +            *largerPtr = matchIndex;
    +            commonLengthLarger = matchLength;
    +            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    +            largerPtr = nextPtr;
    +            matchIndex = nextPtr[0];
    +    }   }
    +
    +    *smallerPtr = *largerPtr = 0;
    +
    +update:
    +    zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
    +    return mnum;
    +}
    +
    +
    +/** Tree updater, providing best match */
    +static U32 ZSTD_BtGetAllMatches (
    +                        ZSTD_CCtx* zc,
    +                        const BYTE* const ip, const BYTE* const iLimit,
    +                        const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
    +{
    +    if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */
    +    ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
    +    return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches, minMatchLen);
    +}
    +
    +
    +static U32 ZSTD_BtGetAllMatches_selectMLS (
    +                        ZSTD_CCtx* zc,   /* Index table will be updated */
    +                        const BYTE* ip, const BYTE* const iHighLimit,
    +                        const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
    +{
    +    switch(matchLengthSearch)
    +    {
    +    case 3 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
    +    default :
    +    case 4 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
    +    case 5 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
    +    case 7 :
    +    case 6 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
    +    }
    +}
    +
    +/** Tree updater, providing best match */
    +static U32 ZSTD_BtGetAllMatches_extDict (
    +                        ZSTD_CCtx* zc,
    +                        const BYTE* const ip, const BYTE* const iLimit,
    +                        const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
    +{
    +    if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */
    +    ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
    +    return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minMatchLen);
    +}
    +
    +
    +static U32 ZSTD_BtGetAllMatches_selectMLS_extDict (
    +                        ZSTD_CCtx* zc,   /* Index table will be updated */
    +                        const BYTE* ip, const BYTE* const iHighLimit,
    +                        const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
    +{
    +    switch(matchLengthSearch)
    +    {
    +    case 3 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
    +    default :
    +    case 4 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
    +    case 5 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
    +    case 7 :
    +    case 6 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
    +    }
    +}
    +
    +
    +/*-*******************************
    +*  Optimal parser
    +*********************************/
    +FORCE_INLINE_TEMPLATE
    +void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
    +                                    const void* src, size_t srcSize, const int ultra)
    +{
    +    seqStore_t* seqStorePtr = &(ctx->seqStore);
    +    optState_t* optStatePtr = &(ctx->optState);
    +    const BYTE* const istart = (const BYTE*)src;
    +    const BYTE* ip = istart;
    +    const BYTE* anchor = istart;
    +    const BYTE* const iend = istart + srcSize;
    +    const BYTE* const ilimit = iend - 8;
    +    const BYTE* const base = ctx->base;
    +    const BYTE* const prefixStart = base + ctx->dictLimit;
    +
    +    const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
    +    const U32 sufficient_len = ctx->appliedParams.cParams.targetLength;
    +    const U32 mls = ctx->appliedParams.cParams.searchLength;
    +    const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
    +
    +    ZSTD_optimal_t* opt = optStatePtr->priceTable;
    +    ZSTD_match_t* matches = optStatePtr->matchTable;
    +    const BYTE* inr;
    +    U32 offset, rep[ZSTD_REP_NUM];
    +
    +    /* init */
    +    ctx->nextToUpdate3 = ctx->nextToUpdate;
    +    ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
    +    ip += (ip==prefixStart);
    +    { U32 i; for (i=0; irep[i]; }
    +
    +    /* Match Loop */
    +    while (ip < ilimit) {
    +        U32 cur, match_num, last_pos, litlen, price;
    +        U32 u, mlen, best_mlen, best_off, litLength;
    +        memset(opt, 0, sizeof(ZSTD_optimal_t));
    +        last_pos = 0;
    +        litlen = (U32)(ip - anchor);
    +
    +        /* check repCode */
    +        {   U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
    +            for (i=(ip == anchor); i 0) && (repCur < (S32)(ip-prefixStart))
    +                    && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repCur, minMatch))) {
    +                    mlen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repCur, iend) + minMatch;
    +                    if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
    +                        best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
    +                        goto _storeSequence;
    +                    }
    +                    best_off = i - (ip == anchor);
    +                    do {
    +                        price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
    +                        if (mlen > last_pos || price < opt[mlen].price)
    +                            SET_PRICE(mlen, mlen, i, litlen, price);   /* note : macro modifies last_pos */
    +                        mlen--;
    +                    } while (mlen >= minMatch);
    +        }   }   }
    +
    +        match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, ip, iend, maxSearches, mls, matches, minMatch);
    +
    +        if (!last_pos && !match_num) { ip++; continue; }
    +
    +        if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
    +            best_mlen = matches[match_num-1].len;
    +            best_off = matches[match_num-1].off;
    +            cur = 0;
    +            last_pos = 1;
    +            goto _storeSequence;
    +        }
    +
    +        /* set prices using matches at position = 0 */
    +        best_mlen = (last_pos) ? last_pos : minMatch;
    +        for (u = 0; u < match_num; u++) {
    +            mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
    +            best_mlen = matches[u].len;
    +            while (mlen <= best_mlen) {
    +                price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
    +                if (mlen > last_pos || price < opt[mlen].price)
    +                    SET_PRICE(mlen, mlen, matches[u].off, litlen, price);   /* note : macro modifies last_pos */
    +                mlen++;
    +        }   }
    +
    +        if (last_pos < minMatch) { ip++; continue; }
    +
    +        /* initialize opt[0] */
    +        { U32 i ; for (i=0; i litlen) {
    +                    price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen);
    +                } else
    +                    price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor);
    +           } else {
    +                litlen = 1;
    +                price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1);
    +           }
    +
    +           if (cur > last_pos || price <= opt[cur].price)
    +                SET_PRICE(cur, 1, 0, litlen, price);
    +
    +           if (cur == last_pos) break;
    +
    +           if (inr > ilimit)  /* last match must start at a minimum distance of 8 from oend */
    +               continue;
    +
    +           mlen = opt[cur].mlen;
    +           if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
    +                opt[cur].rep[2] = opt[cur-mlen].rep[1];
    +                opt[cur].rep[1] = opt[cur-mlen].rep[0];
    +                opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
    +           } else {
    +                opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
    +                opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
    +                opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
    +           }
    +
    +            best_mlen = minMatch;
    +            {   U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
    +                for (i=(opt[cur].mlen != 1); i 0) && (repCur < (S32)(inr-prefixStart))
    +                       && (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(inr - repCur, minMatch))) {
    +                       mlen = (U32)ZSTD_count(inr+minMatch, inr+minMatch - repCur, iend) + minMatch;
    +
    +                       if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
    +                            best_mlen = mlen; best_off = i; last_pos = cur + 1;
    +                            goto _storeSequence;
    +                       }
    +
    +                       best_off = i - (opt[cur].mlen != 1);
    +                       if (mlen > best_mlen) best_mlen = mlen;
    +
    +                       do {
    +                           if (opt[cur].mlen == 1) {
    +                                litlen = opt[cur].litlen;
    +                                if (cur > litlen) {
    +                                    price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
    +                                } else
    +                                    price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
    +                            } else {
    +                                litlen = 0;
    +                                price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
    +                            }
    +
    +                            if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
    +                                SET_PRICE(cur + mlen, mlen, i, litlen, price);
    +                            mlen--;
    +                        } while (mlen >= minMatch);
    +            }   }   }
    +
    +            match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, inr, iend, maxSearches, mls, matches, best_mlen);
    +
    +            if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
    +                best_mlen = matches[match_num-1].len;
    +                best_off = matches[match_num-1].off;
    +                last_pos = cur + 1;
    +                goto _storeSequence;
    +            }
    +
    +            /* set prices using matches at position = cur */
    +            for (u = 0; u < match_num; u++) {
    +                mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
    +                best_mlen = matches[u].len;
    +
    +                while (mlen <= best_mlen) {
    +                    if (opt[cur].mlen == 1) {
    +                        litlen = opt[cur].litlen;
    +                        if (cur > litlen)
    +                            price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
    +                        else
    +                            price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
    +                    } else {
    +                        litlen = 0;
    +                        price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
    +                    }
    +
    +                    if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
    +                        SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
    +
    +                    mlen++;
    +        }   }   }
    +
    +        best_mlen = opt[last_pos].mlen;
    +        best_off = opt[last_pos].off;
    +        cur = last_pos - best_mlen;
    +
    +        /* store sequence */
    +_storeSequence:   /* cur, last_pos, best_mlen, best_off have to be set */
    +        opt[0].mlen = 1;
    +
    +        while (1) {
    +            mlen = opt[cur].mlen;
    +            offset = opt[cur].off;
    +            opt[cur].mlen = best_mlen;
    +            opt[cur].off = best_off;
    +            best_mlen = mlen;
    +            best_off = offset;
    +            if (mlen > cur) break;
    +            cur -= mlen;
    +        }
    +
    +        for (u = 0; u <= last_pos;) {
    +            u += opt[u].mlen;
    +        }
    +
    +        for (cur=0; cur < last_pos; ) {
    +            mlen = opt[cur].mlen;
    +            if (mlen == 1) { ip++; cur++; continue; }
    +            offset = opt[cur].off;
    +            cur += mlen;
    +            litLength = (U32)(ip - anchor);
    +
    +            if (offset > ZSTD_REP_MOVE_OPT) {
    +                rep[2] = rep[1];
    +                rep[1] = rep[0];
    +                rep[0] = offset - ZSTD_REP_MOVE_OPT;
    +                offset--;
    +            } else {
    +                if (offset != 0) {
    +                    best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
    +                    if (offset != 1) rep[2] = rep[1];
    +                    rep[1] = rep[0];
    +                    rep[0] = best_off;
    +                }
    +                if (litLength==0) offset--;
    +            }
    +
    +            ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH);
    +            ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
    +            anchor = ip = ip + mlen;
    +    }    }   /* for (cur=0; cur < last_pos; ) */
    +
    +    /* Save reps for next block */
    +    { int i; for (i=0; irepToConfirm[i] = rep[i]; }
    +
    +    /* Last Literals */
    +    {   size_t const lastLLSize = iend - anchor;
    +        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    +        seqStorePtr->lit += lastLLSize;
    +    }
    +}
    +
    +
    +void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    +{
    +    ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
    +}
    +
    +void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    +{
    +    ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
    +}
    +
    +
    +FORCE_INLINE_TEMPLATE
    +void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx,
    +                                     const void* src, size_t srcSize, const int ultra)
    +{
    +    seqStore_t* seqStorePtr = &(ctx->seqStore);
    +    optState_t* optStatePtr = &(ctx->optState);
    +    const BYTE* const istart = (const BYTE*)src;
    +    const BYTE* ip = istart;
    +    const BYTE* anchor = istart;
    +    const BYTE* const iend = istart + srcSize;
    +    const BYTE* const ilimit = iend - 8;
    +    const BYTE* const base = ctx->base;
    +    const U32 lowestIndex = ctx->lowLimit;
    +    const U32 dictLimit = ctx->dictLimit;
    +    const BYTE* const prefixStart = base + dictLimit;
    +    const BYTE* const dictBase = ctx->dictBase;
    +    const BYTE* const dictEnd  = dictBase + dictLimit;
    +
    +    const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
    +    const U32 sufficient_len = ctx->appliedParams.cParams.targetLength;
    +    const U32 mls = ctx->appliedParams.cParams.searchLength;
    +    const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
    +
    +    ZSTD_optimal_t* opt = optStatePtr->priceTable;
    +    ZSTD_match_t* matches = optStatePtr->matchTable;
    +    const BYTE* inr;
    +
    +    /* init */
    +    U32 offset, rep[ZSTD_REP_NUM];
    +    { U32 i; for (i=0; irep[i]; }
    +
    +    ctx->nextToUpdate3 = ctx->nextToUpdate;
    +    ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
    +    ip += (ip==prefixStart);
    +
    +    /* Match Loop */
    +    while (ip < ilimit) {
    +        U32 cur, match_num, last_pos, litlen, price;
    +        U32 u, mlen, best_mlen, best_off, litLength;
    +        U32 current = (U32)(ip-base);
    +        memset(opt, 0, sizeof(ZSTD_optimal_t));
    +        last_pos = 0;
    +        opt[0].litlen = (U32)(ip - anchor);
    +
    +        /* check repCode */
    +        {   U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
    +            for (i = (ip==anchor); i 0 && repCur <= (S32)current)
    +                   && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex))  /* intentional overflow */
    +                   && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
    +                    /* repcode detected we should take it */
    +                    const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
    +                    mlen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
    +
    +                    if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
    +                        best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
    +                        goto _storeSequence;
    +                    }
    +
    +                    best_off = i - (ip==anchor);
    +                    litlen = opt[0].litlen;
    +                    do {
    +                        price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
    +                        if (mlen > last_pos || price < opt[mlen].price)
    +                            SET_PRICE(mlen, mlen, i, litlen, price);   /* note : macro modifies last_pos */
    +                        mlen--;
    +                    } while (mlen >= minMatch);
    +        }   }   }
    +
    +        match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, ip, iend, maxSearches, mls, matches, minMatch);  /* first search (depth 0) */
    +
    +        if (!last_pos && !match_num) { ip++; continue; }
    +
    +        { U32 i; for (i=0; i sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
    +            best_mlen = matches[match_num-1].len;
    +            best_off = matches[match_num-1].off;
    +            cur = 0;
    +            last_pos = 1;
    +            goto _storeSequence;
    +        }
    +
    +        best_mlen = (last_pos) ? last_pos : minMatch;
    +
    +        /* set prices using matches at position = 0 */
    +        for (u = 0; u < match_num; u++) {
    +            mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
    +            best_mlen = matches[u].len;
    +            litlen = opt[0].litlen;
    +            while (mlen <= best_mlen) {
    +                price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
    +                if (mlen > last_pos || price < opt[mlen].price)
    +                    SET_PRICE(mlen, mlen, matches[u].off, litlen, price);
    +                mlen++;
    +        }   }
    +
    +        if (last_pos < minMatch) {
    +            ip++; continue;
    +        }
    +
    +        /* check further positions */
    +        for (cur = 1; cur <= last_pos; cur++) {
    +            inr = ip + cur;
    +
    +            if (opt[cur-1].mlen == 1) {
    +                litlen = opt[cur-1].litlen + 1;
    +                if (cur > litlen) {
    +                    price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen);
    +                } else
    +                    price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor);
    +            } else {
    +                litlen = 1;
    +                price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1);
    +            }
    +
    +            if (cur > last_pos || price <= opt[cur].price)
    +                SET_PRICE(cur, 1, 0, litlen, price);
    +
    +            if (cur == last_pos) break;
    +
    +            if (inr > ilimit)  /* last match must start at a minimum distance of 8 from oend */
    +                continue;
    +
    +            mlen = opt[cur].mlen;
    +            if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
    +                opt[cur].rep[2] = opt[cur-mlen].rep[1];
    +                opt[cur].rep[1] = opt[cur-mlen].rep[0];
    +                opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
    +            } else {
    +                opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
    +                opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
    +                opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
    +            }
    +
    +            best_mlen = minMatch;
    +            {   U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
    +                for (i = (mlen != 1); i 0 && repCur <= (S32)(current+cur))
    +                      && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex))  /* intentional overflow */
    +                      && (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
    +                        /* repcode detected */
    +                        const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
    +                        mlen = (U32)ZSTD_count_2segments(inr+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
    +
    +                        if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
    +                            best_mlen = mlen; best_off = i; last_pos = cur + 1;
    +                            goto _storeSequence;
    +                        }
    +
    +                        best_off = i - (opt[cur].mlen != 1);
    +                        if (mlen > best_mlen) best_mlen = mlen;
    +
    +                        do {
    +                            if (opt[cur].mlen == 1) {
    +                                litlen = opt[cur].litlen;
    +                                if (cur > litlen) {
    +                                    price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
    +                                } else
    +                                    price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
    +                            } else {
    +                                litlen = 0;
    +                                price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
    +                            }
    +
    +                            if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
    +                                SET_PRICE(cur + mlen, mlen, i, litlen, price);
    +                            mlen--;
    +                        } while (mlen >= minMatch);
    +            }   }   }
    +
    +            match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, inr, iend, maxSearches, mls, matches, minMatch);
    +
    +            if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
    +                best_mlen = matches[match_num-1].len;
    +                best_off = matches[match_num-1].off;
    +                last_pos = cur + 1;
    +                goto _storeSequence;
    +            }
    +
    +            /* set prices using matches at position = cur */
    +            for (u = 0; u < match_num; u++) {
    +                mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
    +                best_mlen = matches[u].len;
    +
    +                while (mlen <= best_mlen) {
    +                    if (opt[cur].mlen == 1) {
    +                        litlen = opt[cur].litlen;
    +                        if (cur > litlen)
    +                            price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
    +                        else
    +                            price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
    +                    } else {
    +                        litlen = 0;
    +                        price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
    +                    }
    +
    +                    if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
    +                        SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
    +
    +                    mlen++;
    +        }   }   }   /* for (cur = 1; cur <= last_pos; cur++) */
    +
    +        best_mlen = opt[last_pos].mlen;
    +        best_off = opt[last_pos].off;
    +        cur = last_pos - best_mlen;
    +
    +        /* store sequence */
    +_storeSequence:   /* cur, last_pos, best_mlen, best_off have to be set */
    +        opt[0].mlen = 1;
    +
    +        while (1) {
    +            mlen = opt[cur].mlen;
    +            offset = opt[cur].off;
    +            opt[cur].mlen = best_mlen;
    +            opt[cur].off = best_off;
    +            best_mlen = mlen;
    +            best_off = offset;
    +            if (mlen > cur) break;
    +            cur -= mlen;
    +        }
    +
    +        for (u = 0; u <= last_pos; ) {
    +            u += opt[u].mlen;
    +        }
    +
    +        for (cur=0; cur < last_pos; ) {
    +            mlen = opt[cur].mlen;
    +            if (mlen == 1) { ip++; cur++; continue; }
    +            offset = opt[cur].off;
    +            cur += mlen;
    +            litLength = (U32)(ip - anchor);
    +
    +            if (offset > ZSTD_REP_MOVE_OPT) {
    +                rep[2] = rep[1];
    +                rep[1] = rep[0];
    +                rep[0] = offset - ZSTD_REP_MOVE_OPT;
    +                offset--;
    +            } else {
    +                if (offset != 0) {
    +                    best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
    +                    if (offset != 1) rep[2] = rep[1];
    +                    rep[1] = rep[0];
    +                    rep[0] = best_off;
    +                }
    +
    +                if (litLength==0) offset--;
    +            }
    +
    +            ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH);
    +            ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
    +            anchor = ip = ip + mlen;
    +    }    }   /* for (cur=0; cur < last_pos; ) */
    +
    +    /* Save reps for next block */
    +    { int i; for (i=0; irepToConfirm[i] = rep[i]; }
    +
    +    /* Last Literals */
    +    {   size_t lastLLSize = iend - anchor;
    +        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    +        seqStorePtr->lit += lastLLSize;
    +    }
    +}
    +
    +
    +void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    +{
    +    ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
    +}
    +
    +void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
    +{
    +    ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
    +}
    diff --git a/lib/compress/zstd_opt.h b/lib/compress/zstd_opt.h
    index 4d938c80d..0991a1f13 100644
    --- a/lib/compress/zstd_opt.h
    +++ b/lib/compress/zstd_opt.h
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
    + * 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
    @@ -7,932 +7,23 @@
      * in the COPYING file in the root directory of this source tree).
      */
     
    +#ifndef ZSTD_OPT_H
    +#define ZSTD_OPT_H
     
    -/* Note : this file is intended to be included within zstd_compress.c */
    +#include "zstd_compress.h"
     
    +#if defined (__cplusplus)
    +extern "C" {
    +#endif
     
    -#ifndef ZSTD_OPT_H_91842398743
    -#define ZSTD_OPT_H_91842398743
    +void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
    +void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
     
    +void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
    +void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
     
    -#define ZSTD_LITFREQ_ADD    2
    -#define ZSTD_FREQ_DIV       4
    -#define ZSTD_MAX_PRICE      (1<<30)
    -
    -/*-*************************************
    -*  Price functions for optimal parser
    -***************************************/
    -static void ZSTD_setLog2Prices(optState_t* optPtr)
    -{
    -    optPtr->log2matchLengthSum = ZSTD_highbit32(optPtr->matchLengthSum+1);
    -    optPtr->log2litLengthSum = ZSTD_highbit32(optPtr->litLengthSum+1);
    -    optPtr->log2litSum = ZSTD_highbit32(optPtr->litSum+1);
    -    optPtr->log2offCodeSum = ZSTD_highbit32(optPtr->offCodeSum+1);
    -    optPtr->factor = 1 + ((optPtr->litSum>>5) / optPtr->litLengthSum) + ((optPtr->litSum<<1) / (optPtr->litSum + optPtr->matchSum));
    +#if defined (__cplusplus)
     }
    +#endif
     
    -
    -static void ZSTD_rescaleFreqs(optState_t* optPtr, const BYTE* src, size_t srcSize)
    -{
    -    unsigned u;
    -
    -    optPtr->cachedLiterals = NULL;
    -    optPtr->cachedPrice = optPtr->cachedLitLength = 0;
    -    optPtr->staticPrices = 0;
    -
    -    if (optPtr->litLengthSum == 0) {
    -        if (srcSize <= 1024) optPtr->staticPrices = 1;
    -
    -        assert(optPtr->litFreq!=NULL);
    -        for (u=0; u<=MaxLit; u++)
    -            optPtr->litFreq[u] = 0;
    -        for (u=0; ulitFreq[src[u]]++;
    -
    -        optPtr->litSum = 0;
    -        optPtr->litLengthSum = MaxLL+1;
    -        optPtr->matchLengthSum = MaxML+1;
    -        optPtr->offCodeSum = (MaxOff+1);
    -        optPtr->matchSum = (ZSTD_LITFREQ_ADD<litFreq[u] = 1 + (optPtr->litFreq[u]>>ZSTD_FREQ_DIV);
    -            optPtr->litSum += optPtr->litFreq[u];
    -        }
    -        for (u=0; u<=MaxLL; u++)
    -            optPtr->litLengthFreq[u] = 1;
    -        for (u=0; u<=MaxML; u++)
    -            optPtr->matchLengthFreq[u] = 1;
    -        for (u=0; u<=MaxOff; u++)
    -            optPtr->offCodeFreq[u] = 1;
    -    } else {
    -        optPtr->matchLengthSum = 0;
    -        optPtr->litLengthSum = 0;
    -        optPtr->offCodeSum = 0;
    -        optPtr->matchSum = 0;
    -        optPtr->litSum = 0;
    -
    -        for (u=0; u<=MaxLit; u++) {
    -            optPtr->litFreq[u] = 1 + (optPtr->litFreq[u]>>(ZSTD_FREQ_DIV+1));
    -            optPtr->litSum += optPtr->litFreq[u];
    -        }
    -        for (u=0; u<=MaxLL; u++) {
    -            optPtr->litLengthFreq[u] = 1 + (optPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1));
    -            optPtr->litLengthSum += optPtr->litLengthFreq[u];
    -        }
    -        for (u=0; u<=MaxML; u++) {
    -            optPtr->matchLengthFreq[u] = 1 + (optPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV);
    -            optPtr->matchLengthSum += optPtr->matchLengthFreq[u];
    -            optPtr->matchSum += optPtr->matchLengthFreq[u] * (u + 3);
    -        }
    -        optPtr->matchSum *= ZSTD_LITFREQ_ADD;
    -        for (u=0; u<=MaxOff; u++) {
    -            optPtr->offCodeFreq[u] = 1 + (optPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV);
    -            optPtr->offCodeSum += optPtr->offCodeFreq[u];
    -        }
    -    }
    -
    -    ZSTD_setLog2Prices(optPtr);
    -}
    -
    -
    -static U32 ZSTD_getLiteralPrice(optState_t* optPtr, U32 litLength, const BYTE* literals)
    -{
    -    U32 price, u;
    -
    -    if (optPtr->staticPrices)
    -        return ZSTD_highbit32((U32)litLength+1) + (litLength*6);
    -
    -    if (litLength == 0)
    -        return optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[0]+1);
    -
    -    /* literals */
    -    if (optPtr->cachedLiterals == literals) {
    -        U32 const additional = litLength - optPtr->cachedLitLength;
    -        const BYTE* literals2 = optPtr->cachedLiterals + optPtr->cachedLitLength;
    -        price = optPtr->cachedPrice + additional * optPtr->log2litSum;
    -        for (u=0; u < additional; u++)
    -            price -= ZSTD_highbit32(optPtr->litFreq[literals2[u]]+1);
    -        optPtr->cachedPrice = price;
    -        optPtr->cachedLitLength = litLength;
    -    } else {
    -        price = litLength * optPtr->log2litSum;
    -        for (u=0; u < litLength; u++)
    -            price -= ZSTD_highbit32(optPtr->litFreq[literals[u]]+1);
    -
    -        if (litLength >= 12) {
    -            optPtr->cachedLiterals = literals;
    -            optPtr->cachedPrice = price;
    -            optPtr->cachedLitLength = litLength;
    -        }
    -    }
    -
    -    /* literal Length */
    -    {   const BYTE LL_deltaCode = 19;
    -        const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
    -        price += LL_bits[llCode] + optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1);
    -    }
    -
    -    return price;
    -}
    -
    -
    -FORCE_INLINE_TEMPLATE U32 ZSTD_getPrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength, const int ultra)
    -{
    -    /* offset */
    -    U32 price;
    -    BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
    -
    -    if (optPtr->staticPrices)
    -        return ZSTD_getLiteralPrice(optPtr, litLength, literals) + ZSTD_highbit32((U32)matchLength+1) + 16 + offCode;
    -
    -    price = offCode + optPtr->log2offCodeSum - ZSTD_highbit32(optPtr->offCodeFreq[offCode]+1);
    -    if (!ultra && offCode >= 20) price += (offCode-19)*2;
    -
    -    /* match Length */
    -    {   const BYTE ML_deltaCode = 36;
    -        const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
    -        price += ML_bits[mlCode] + optPtr->log2matchLengthSum - ZSTD_highbit32(optPtr->matchLengthFreq[mlCode]+1);
    -    }
    -
    -    return price + ZSTD_getLiteralPrice(optPtr, litLength, literals) + optPtr->factor;
    -}
    -
    -
    -static void ZSTD_updatePrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength)
    -{
    -    U32 u;
    -
    -    /* literals */
    -    optPtr->litSum += litLength*ZSTD_LITFREQ_ADD;
    -    for (u=0; u < litLength; u++)
    -        optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
    -
    -    /* literal Length */
    -    {   const BYTE LL_deltaCode = 19;
    -        const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
    -        optPtr->litLengthFreq[llCode]++;
    -        optPtr->litLengthSum++;
    -    }
    -
    -    /* match offset */
    -    {   BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
    -        optPtr->offCodeSum++;
    -        optPtr->offCodeFreq[offCode]++;
    -    }
    -
    -    /* match Length */
    -    {   const BYTE ML_deltaCode = 36;
    -        const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
    -        optPtr->matchLengthFreq[mlCode]++;
    -        optPtr->matchLengthSum++;
    -    }
    -
    -    ZSTD_setLog2Prices(optPtr);
    -}
    -
    -
    -#define SET_PRICE(pos, mlen_, offset_, litlen_, price_)   \
    -    {                                                 \
    -        while (last_pos < pos)  { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } \
    -        opt[pos].mlen = mlen_;                         \
    -        opt[pos].off = offset_;                        \
    -        opt[pos].litlen = litlen_;                     \
    -        opt[pos].price = price_;                       \
    -    }
    -
    -
    -/* function safe only for comparisons */
    -static U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
    -{
    -    switch (length)
    -    {
    -    default :
    -    case 4 : return MEM_read32(memPtr);
    -    case 3 : if (MEM_isLittleEndian())
    -                return MEM_read32(memPtr)<<8;
    -             else
    -                return MEM_read32(memPtr)>>8;
    -    }
    -}
    -
    -
    -/* Update hashTable3 up to ip (excluded)
    -   Assumption : always within prefix (i.e. not within extDict) */
    -static
    -U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* zc, const BYTE* ip)
    -{
    -    U32* const hashTable3  = zc->hashTable3;
    -    U32 const hashLog3  = zc->hashLog3;
    -    const BYTE* const base = zc->base;
    -    U32 idx = zc->nextToUpdate3;
    -    const U32 target = zc->nextToUpdate3 = (U32)(ip - base);
    -    const size_t hash3 = ZSTD_hash3Ptr(ip, hashLog3);
    -
    -    while(idx < target) {
    -        hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
    -        idx++;
    -    }
    -
    -    return hashTable3[hash3];
    -}
    -
    -
    -/*-*************************************
    -*  Binary Tree search
    -***************************************/
    -static U32 ZSTD_insertBtAndGetAllMatches (
    -                        ZSTD_CCtx* zc,
    -                        const BYTE* const ip, const BYTE* const iLimit,
    -                        U32 nbCompares, const U32 mls,
    -                        U32 extDict, ZSTD_match_t* matches, const U32 minMatchLen)
    -{
    -    const BYTE* const base = zc->base;
    -    const U32 current = (U32)(ip-base);
    -    const U32 hashLog = zc->appliedParams.cParams.hashLog;
    -    const size_t h  = ZSTD_hashPtr(ip, hashLog, mls);
    -    U32* const hashTable = zc->hashTable;
    -    U32 matchIndex  = hashTable[h];
    -    U32* const bt   = zc->chainTable;
    -    const U32 btLog = zc->appliedParams.cParams.chainLog - 1;
    -    const U32 btMask= (1U << btLog) - 1;
    -    size_t commonLengthSmaller=0, commonLengthLarger=0;
    -    const BYTE* const dictBase = zc->dictBase;
    -    const U32 dictLimit = zc->dictLimit;
    -    const BYTE* const dictEnd = dictBase + dictLimit;
    -    const BYTE* const prefixStart = base + dictLimit;
    -    const U32 btLow = btMask >= current ? 0 : current - btMask;
    -    const U32 windowLow = zc->lowLimit;
    -    U32* smallerPtr = bt + 2*(current&btMask);
    -    U32* largerPtr  = bt + 2*(current&btMask) + 1;
    -    U32 matchEndIdx = current+8;
    -    U32 dummy32;   /* to be nullified at the end */
    -    U32 mnum = 0;
    -
    -    const U32 minMatch = (mls == 3) ? 3 : 4;
    -    size_t bestLength = minMatchLen-1;
    -
    -    if (minMatch == 3) { /* HC3 match finder */
    -        U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip);
    -        if (matchIndex3>windowLow && (current - matchIndex3 < (1<<18))) {
    -            const BYTE* match;
    -            size_t currentMl=0;
    -            if ((!extDict) || matchIndex3 >= dictLimit) {
    -                match = base + matchIndex3;
    -                if (match[bestLength] == ip[bestLength]) currentMl = ZSTD_count(ip, match, iLimit);
    -            } else {
    -                match = dictBase + matchIndex3;
    -                if (ZSTD_readMINMATCH(match, MINMATCH) == ZSTD_readMINMATCH(ip, MINMATCH))    /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */
    -                    currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
    -            }
    -
    -            /* save best solution */
    -            if (currentMl > bestLength) {
    -                bestLength = currentMl;
    -                matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex3;
    -                matches[mnum].len = (U32)currentMl;
    -                mnum++;
    -                if (currentMl > ZSTD_OPT_NUM) goto update;
    -                if (ip+currentMl == iLimit) goto update; /* best possible, and avoid read overflow*/
    -            }
    -        }
    -    }
    -
    -    hashTable[h] = current;   /* Update Hash Table */
    -
    -    while (nbCompares-- && (matchIndex > windowLow)) {
    -        U32* nextPtr = bt + 2*(matchIndex & btMask);
    -        size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
    -        const BYTE* match;
    -
    -        if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
    -            match = base + matchIndex;
    -            if (match[matchLength] == ip[matchLength]) {
    -                matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iLimit) +1;
    -            }
    -        } else {
    -            match = dictBase + matchIndex;
    -            matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
    -            if (matchIndex+matchLength >= dictLimit)
    -                match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */
    -        }
    -
    -        if (matchLength > bestLength) {
    -            if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength;
    -            bestLength = matchLength;
    -            matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex;
    -            matches[mnum].len = (U32)matchLength;
    -            mnum++;
    -            if (matchLength > ZSTD_OPT_NUM) break;
    -            if (ip+matchLength == iLimit)   /* equal : no way to know if inf or sup */
    -                break;   /* drop, to guarantee consistency (miss a little bit of compression) */
    -        }
    -
    -        if (match[matchLength] < ip[matchLength]) {
    -            /* match is smaller than current */
    -            *smallerPtr = matchIndex;             /* update smaller idx */
    -            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
    -            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    -            smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */
    -            matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
    -        } else {
    -            /* match is larger than current */
    -            *largerPtr = matchIndex;
    -            commonLengthLarger = matchLength;
    -            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
    -            largerPtr = nextPtr;
    -            matchIndex = nextPtr[0];
    -    }   }
    -
    -    *smallerPtr = *largerPtr = 0;
    -
    -update:
    -    zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
    -    return mnum;
    -}
    -
    -
    -/** Tree updater, providing best match */
    -static U32 ZSTD_BtGetAllMatches (
    -                        ZSTD_CCtx* zc,
    -                        const BYTE* const ip, const BYTE* const iLimit,
    -                        const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
    -{
    -    if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */
    -    ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
    -    return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches, minMatchLen);
    -}
    -
    -
    -static U32 ZSTD_BtGetAllMatches_selectMLS (
    -                        ZSTD_CCtx* zc,   /* Index table will be updated */
    -                        const BYTE* ip, const BYTE* const iHighLimit,
    -                        const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
    -{
    -    switch(matchLengthSearch)
    -    {
    -    case 3 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
    -    default :
    -    case 4 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
    -    case 5 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
    -    case 7 :
    -    case 6 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
    -    }
    -}
    -
    -/** Tree updater, providing best match */
    -static U32 ZSTD_BtGetAllMatches_extDict (
    -                        ZSTD_CCtx* zc,
    -                        const BYTE* const ip, const BYTE* const iLimit,
    -                        const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
    -{
    -    if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */
    -    ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
    -    return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minMatchLen);
    -}
    -
    -
    -static U32 ZSTD_BtGetAllMatches_selectMLS_extDict (
    -                        ZSTD_CCtx* zc,   /* Index table will be updated */
    -                        const BYTE* ip, const BYTE* const iHighLimit,
    -                        const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
    -{
    -    switch(matchLengthSearch)
    -    {
    -    case 3 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
    -    default :
    -    case 4 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
    -    case 5 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
    -    case 7 :
    -    case 6 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
    -    }
    -}
    -
    -
    -/*-*******************************
    -*  Optimal parser
    -*********************************/
    -FORCE_INLINE_TEMPLATE
    -void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
    -                                    const void* src, size_t srcSize, const int ultra)
    -{
    -    seqStore_t* seqStorePtr = &(ctx->seqStore);
    -    optState_t* optStatePtr = &(ctx->optState);
    -    const BYTE* const istart = (const BYTE*)src;
    -    const BYTE* ip = istart;
    -    const BYTE* anchor = istart;
    -    const BYTE* const iend = istart + srcSize;
    -    const BYTE* const ilimit = iend - 8;
    -    const BYTE* const base = ctx->base;
    -    const BYTE* const prefixStart = base + ctx->dictLimit;
    -
    -    const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
    -    const U32 sufficient_len = ctx->appliedParams.cParams.targetLength;
    -    const U32 mls = ctx->appliedParams.cParams.searchLength;
    -    const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
    -
    -    ZSTD_optimal_t* opt = optStatePtr->priceTable;
    -    ZSTD_match_t* matches = optStatePtr->matchTable;
    -    const BYTE* inr;
    -    U32 offset, rep[ZSTD_REP_NUM];
    -
    -    /* init */
    -    ctx->nextToUpdate3 = ctx->nextToUpdate;
    -    ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
    -    ip += (ip==prefixStart);
    -    { U32 i; for (i=0; irep[i]; }
    -
    -    /* Match Loop */
    -    while (ip < ilimit) {
    -        U32 cur, match_num, last_pos, litlen, price;
    -        U32 u, mlen, best_mlen, best_off, litLength;
    -        memset(opt, 0, sizeof(ZSTD_optimal_t));
    -        last_pos = 0;
    -        litlen = (U32)(ip - anchor);
    -
    -        /* check repCode */
    -        {   U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
    -            for (i=(ip == anchor); i 0) && (repCur < (S32)(ip-prefixStart))
    -                    && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repCur, minMatch))) {
    -                    mlen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repCur, iend) + minMatch;
    -                    if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
    -                        best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
    -                        goto _storeSequence;
    -                    }
    -                    best_off = i - (ip == anchor);
    -                    do {
    -                        price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
    -                        if (mlen > last_pos || price < opt[mlen].price)
    -                            SET_PRICE(mlen, mlen, i, litlen, price);   /* note : macro modifies last_pos */
    -                        mlen--;
    -                    } while (mlen >= minMatch);
    -        }   }   }
    -
    -        match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, ip, iend, maxSearches, mls, matches, minMatch);
    -
    -        if (!last_pos && !match_num) { ip++; continue; }
    -
    -        if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
    -            best_mlen = matches[match_num-1].len;
    -            best_off = matches[match_num-1].off;
    -            cur = 0;
    -            last_pos = 1;
    -            goto _storeSequence;
    -        }
    -
    -        /* set prices using matches at position = 0 */
    -        best_mlen = (last_pos) ? last_pos : minMatch;
    -        for (u = 0; u < match_num; u++) {
    -            mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
    -            best_mlen = matches[u].len;
    -            while (mlen <= best_mlen) {
    -                price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
    -                if (mlen > last_pos || price < opt[mlen].price)
    -                    SET_PRICE(mlen, mlen, matches[u].off, litlen, price);   /* note : macro modifies last_pos */
    -                mlen++;
    -        }   }
    -
    -        if (last_pos < minMatch) { ip++; continue; }
    -
    -        /* initialize opt[0] */
    -        { U32 i ; for (i=0; i litlen) {
    -                    price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen);
    -                } else
    -                    price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor);
    -           } else {
    -                litlen = 1;
    -                price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1);
    -           }
    -
    -           if (cur > last_pos || price <= opt[cur].price)
    -                SET_PRICE(cur, 1, 0, litlen, price);
    -
    -           if (cur == last_pos) break;
    -
    -           if (inr > ilimit)  /* last match must start at a minimum distance of 8 from oend */
    -               continue;
    -
    -           mlen = opt[cur].mlen;
    -           if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
    -                opt[cur].rep[2] = opt[cur-mlen].rep[1];
    -                opt[cur].rep[1] = opt[cur-mlen].rep[0];
    -                opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
    -           } else {
    -                opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
    -                opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
    -                opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
    -           }
    -
    -            best_mlen = minMatch;
    -            {   U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
    -                for (i=(opt[cur].mlen != 1); i 0) && (repCur < (S32)(inr-prefixStart))
    -                       && (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(inr - repCur, minMatch))) {
    -                       mlen = (U32)ZSTD_count(inr+minMatch, inr+minMatch - repCur, iend) + minMatch;
    -
    -                       if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
    -                            best_mlen = mlen; best_off = i; last_pos = cur + 1;
    -                            goto _storeSequence;
    -                       }
    -
    -                       best_off = i - (opt[cur].mlen != 1);
    -                       if (mlen > best_mlen) best_mlen = mlen;
    -
    -                       do {
    -                           if (opt[cur].mlen == 1) {
    -                                litlen = opt[cur].litlen;
    -                                if (cur > litlen) {
    -                                    price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
    -                                } else
    -                                    price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
    -                            } else {
    -                                litlen = 0;
    -                                price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
    -                            }
    -
    -                            if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
    -                                SET_PRICE(cur + mlen, mlen, i, litlen, price);
    -                            mlen--;
    -                        } while (mlen >= minMatch);
    -            }   }   }
    -
    -            match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, inr, iend, maxSearches, mls, matches, best_mlen);
    -
    -            if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
    -                best_mlen = matches[match_num-1].len;
    -                best_off = matches[match_num-1].off;
    -                last_pos = cur + 1;
    -                goto _storeSequence;
    -            }
    -
    -            /* set prices using matches at position = cur */
    -            for (u = 0; u < match_num; u++) {
    -                mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
    -                best_mlen = matches[u].len;
    -
    -                while (mlen <= best_mlen) {
    -                    if (opt[cur].mlen == 1) {
    -                        litlen = opt[cur].litlen;
    -                        if (cur > litlen)
    -                            price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
    -                        else
    -                            price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
    -                    } else {
    -                        litlen = 0;
    -                        price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
    -                    }
    -
    -                    if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
    -                        SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
    -
    -                    mlen++;
    -        }   }   }
    -
    -        best_mlen = opt[last_pos].mlen;
    -        best_off = opt[last_pos].off;
    -        cur = last_pos - best_mlen;
    -
    -        /* store sequence */
    -_storeSequence:   /* cur, last_pos, best_mlen, best_off have to be set */
    -        opt[0].mlen = 1;
    -
    -        while (1) {
    -            mlen = opt[cur].mlen;
    -            offset = opt[cur].off;
    -            opt[cur].mlen = best_mlen;
    -            opt[cur].off = best_off;
    -            best_mlen = mlen;
    -            best_off = offset;
    -            if (mlen > cur) break;
    -            cur -= mlen;
    -        }
    -
    -        for (u = 0; u <= last_pos;) {
    -            u += opt[u].mlen;
    -        }
    -
    -        for (cur=0; cur < last_pos; ) {
    -            mlen = opt[cur].mlen;
    -            if (mlen == 1) { ip++; cur++; continue; }
    -            offset = opt[cur].off;
    -            cur += mlen;
    -            litLength = (U32)(ip - anchor);
    -
    -            if (offset > ZSTD_REP_MOVE_OPT) {
    -                rep[2] = rep[1];
    -                rep[1] = rep[0];
    -                rep[0] = offset - ZSTD_REP_MOVE_OPT;
    -                offset--;
    -            } else {
    -                if (offset != 0) {
    -                    best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
    -                    if (offset != 1) rep[2] = rep[1];
    -                    rep[1] = rep[0];
    -                    rep[0] = best_off;
    -                }
    -                if (litLength==0) offset--;
    -            }
    -
    -            ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH);
    -            ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
    -            anchor = ip = ip + mlen;
    -    }    }   /* for (cur=0; cur < last_pos; ) */
    -
    -    /* Save reps for next block */
    -    { int i; for (i=0; irepToConfirm[i] = rep[i]; }
    -
    -    /* Last Literals */
    -    {   size_t const lastLLSize = iend - anchor;
    -        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    -        seqStorePtr->lit += lastLLSize;
    -    }
    -}
    -
    -
    -FORCE_INLINE_TEMPLATE
    -void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx,
    -                                     const void* src, size_t srcSize, const int ultra)
    -{
    -    seqStore_t* seqStorePtr = &(ctx->seqStore);
    -    optState_t* optStatePtr = &(ctx->optState);
    -    const BYTE* const istart = (const BYTE*)src;
    -    const BYTE* ip = istart;
    -    const BYTE* anchor = istart;
    -    const BYTE* const iend = istart + srcSize;
    -    const BYTE* const ilimit = iend - 8;
    -    const BYTE* const base = ctx->base;
    -    const U32 lowestIndex = ctx->lowLimit;
    -    const U32 dictLimit = ctx->dictLimit;
    -    const BYTE* const prefixStart = base + dictLimit;
    -    const BYTE* const dictBase = ctx->dictBase;
    -    const BYTE* const dictEnd  = dictBase + dictLimit;
    -
    -    const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
    -    const U32 sufficient_len = ctx->appliedParams.cParams.targetLength;
    -    const U32 mls = ctx->appliedParams.cParams.searchLength;
    -    const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
    -
    -    ZSTD_optimal_t* opt = optStatePtr->priceTable;
    -    ZSTD_match_t* matches = optStatePtr->matchTable;
    -    const BYTE* inr;
    -
    -    /* init */
    -    U32 offset, rep[ZSTD_REP_NUM];
    -    { U32 i; for (i=0; irep[i]; }
    -
    -    ctx->nextToUpdate3 = ctx->nextToUpdate;
    -    ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
    -    ip += (ip==prefixStart);
    -
    -    /* Match Loop */
    -    while (ip < ilimit) {
    -        U32 cur, match_num, last_pos, litlen, price;
    -        U32 u, mlen, best_mlen, best_off, litLength;
    -        U32 current = (U32)(ip-base);
    -        memset(opt, 0, sizeof(ZSTD_optimal_t));
    -        last_pos = 0;
    -        opt[0].litlen = (U32)(ip - anchor);
    -
    -        /* check repCode */
    -        {   U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
    -            for (i = (ip==anchor); i 0 && repCur <= (S32)current)
    -                   && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex))  /* intentional overflow */
    -                   && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
    -                    /* repcode detected we should take it */
    -                    const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
    -                    mlen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
    -
    -                    if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
    -                        best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
    -                        goto _storeSequence;
    -                    }
    -
    -                    best_off = i - (ip==anchor);
    -                    litlen = opt[0].litlen;
    -                    do {
    -                        price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
    -                        if (mlen > last_pos || price < opt[mlen].price)
    -                            SET_PRICE(mlen, mlen, i, litlen, price);   /* note : macro modifies last_pos */
    -                        mlen--;
    -                    } while (mlen >= minMatch);
    -        }   }   }
    -
    -        match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, ip, iend, maxSearches, mls, matches, minMatch);  /* first search (depth 0) */
    -
    -        if (!last_pos && !match_num) { ip++; continue; }
    -
    -        { U32 i; for (i=0; i sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
    -            best_mlen = matches[match_num-1].len;
    -            best_off = matches[match_num-1].off;
    -            cur = 0;
    -            last_pos = 1;
    -            goto _storeSequence;
    -        }
    -
    -        best_mlen = (last_pos) ? last_pos : minMatch;
    -
    -        /* set prices using matches at position = 0 */
    -        for (u = 0; u < match_num; u++) {
    -            mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
    -            best_mlen = matches[u].len;
    -            litlen = opt[0].litlen;
    -            while (mlen <= best_mlen) {
    -                price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
    -                if (mlen > last_pos || price < opt[mlen].price)
    -                    SET_PRICE(mlen, mlen, matches[u].off, litlen, price);
    -                mlen++;
    -        }   }
    -
    -        if (last_pos < minMatch) {
    -            ip++; continue;
    -        }
    -
    -        /* check further positions */
    -        for (cur = 1; cur <= last_pos; cur++) {
    -            inr = ip + cur;
    -
    -            if (opt[cur-1].mlen == 1) {
    -                litlen = opt[cur-1].litlen + 1;
    -                if (cur > litlen) {
    -                    price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen);
    -                } else
    -                    price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor);
    -            } else {
    -                litlen = 1;
    -                price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1);
    -            }
    -
    -            if (cur > last_pos || price <= opt[cur].price)
    -                SET_PRICE(cur, 1, 0, litlen, price);
    -
    -            if (cur == last_pos) break;
    -
    -            if (inr > ilimit)  /* last match must start at a minimum distance of 8 from oend */
    -                continue;
    -
    -            mlen = opt[cur].mlen;
    -            if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
    -                opt[cur].rep[2] = opt[cur-mlen].rep[1];
    -                opt[cur].rep[1] = opt[cur-mlen].rep[0];
    -                opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
    -            } else {
    -                opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
    -                opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
    -                opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
    -            }
    -
    -            best_mlen = minMatch;
    -            {   U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
    -                for (i = (mlen != 1); i 0 && repCur <= (S32)(current+cur))
    -                      && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex))  /* intentional overflow */
    -                      && (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
    -                        /* repcode detected */
    -                        const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
    -                        mlen = (U32)ZSTD_count_2segments(inr+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
    -
    -                        if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
    -                            best_mlen = mlen; best_off = i; last_pos = cur + 1;
    -                            goto _storeSequence;
    -                        }
    -
    -                        best_off = i - (opt[cur].mlen != 1);
    -                        if (mlen > best_mlen) best_mlen = mlen;
    -
    -                        do {
    -                            if (opt[cur].mlen == 1) {
    -                                litlen = opt[cur].litlen;
    -                                if (cur > litlen) {
    -                                    price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
    -                                } else
    -                                    price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
    -                            } else {
    -                                litlen = 0;
    -                                price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
    -                            }
    -
    -                            if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
    -                                SET_PRICE(cur + mlen, mlen, i, litlen, price);
    -                            mlen--;
    -                        } while (mlen >= minMatch);
    -            }   }   }
    -
    -            match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, inr, iend, maxSearches, mls, matches, minMatch);
    -
    -            if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
    -                best_mlen = matches[match_num-1].len;
    -                best_off = matches[match_num-1].off;
    -                last_pos = cur + 1;
    -                goto _storeSequence;
    -            }
    -
    -            /* set prices using matches at position = cur */
    -            for (u = 0; u < match_num; u++) {
    -                mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
    -                best_mlen = matches[u].len;
    -
    -                while (mlen <= best_mlen) {
    -                    if (opt[cur].mlen == 1) {
    -                        litlen = opt[cur].litlen;
    -                        if (cur > litlen)
    -                            price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
    -                        else
    -                            price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
    -                    } else {
    -                        litlen = 0;
    -                        price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
    -                    }
    -
    -                    if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
    -                        SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
    -
    -                    mlen++;
    -        }   }   }   /* for (cur = 1; cur <= last_pos; cur++) */
    -
    -        best_mlen = opt[last_pos].mlen;
    -        best_off = opt[last_pos].off;
    -        cur = last_pos - best_mlen;
    -
    -        /* store sequence */
    -_storeSequence:   /* cur, last_pos, best_mlen, best_off have to be set */
    -        opt[0].mlen = 1;
    -
    -        while (1) {
    -            mlen = opt[cur].mlen;
    -            offset = opt[cur].off;
    -            opt[cur].mlen = best_mlen;
    -            opt[cur].off = best_off;
    -            best_mlen = mlen;
    -            best_off = offset;
    -            if (mlen > cur) break;
    -            cur -= mlen;
    -        }
    -
    -        for (u = 0; u <= last_pos; ) {
    -            u += opt[u].mlen;
    -        }
    -
    -        for (cur=0; cur < last_pos; ) {
    -            mlen = opt[cur].mlen;
    -            if (mlen == 1) { ip++; cur++; continue; }
    -            offset = opt[cur].off;
    -            cur += mlen;
    -            litLength = (U32)(ip - anchor);
    -
    -            if (offset > ZSTD_REP_MOVE_OPT) {
    -                rep[2] = rep[1];
    -                rep[1] = rep[0];
    -                rep[0] = offset - ZSTD_REP_MOVE_OPT;
    -                offset--;
    -            } else {
    -                if (offset != 0) {
    -                    best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
    -                    if (offset != 1) rep[2] = rep[1];
    -                    rep[1] = rep[0];
    -                    rep[0] = best_off;
    -                }
    -
    -                if (litLength==0) offset--;
    -            }
    -
    -            ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH);
    -            ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
    -            anchor = ip = ip + mlen;
    -    }    }   /* for (cur=0; cur < last_pos; ) */
    -
    -    /* Save reps for next block */
    -    { int i; for (i=0; irepToConfirm[i] = rep[i]; }
    -
    -    /* Last Literals */
    -    {   size_t lastLLSize = iend - anchor;
    -        memcpy(seqStorePtr->lit, anchor, lastLLSize);
    -        seqStorePtr->lit += lastLLSize;
    -    }
    -}
    -
    -#endif  /* ZSTD_OPT_H_91842398743 */
    +#endif /* ZSTD_OPT_H */
    
    From a4eac0db2916592f073011c971e822c4329a063d Mon Sep 17 00:00:00 2001
    From: Nick Terrell 
    Date: Fri, 1 Sep 2017 18:22:31 -0700
    Subject: [PATCH 103/248] Update build scripts
    
    ---
     build/VS2008/fullbench/fullbench.vcproj      | 36 +++++++++++++++++-
     build/VS2008/fuzzer/fuzzer.vcproj            | 36 +++++++++++++++++-
     build/VS2008/zstd/zstd.vcproj                | 40 ++++++++++++++++++--
     build/VS2008/zstdlib/zstdlib.vcproj          | 36 +++++++++++++++++-
     build/VS2010/fullbench/fullbench.vcxproj     |  8 ++++
     build/VS2010/fuzzer/fuzzer.vcxproj           |  8 ++++
     build/VS2010/libzstd-dll/libzstd-dll.vcxproj |  8 ++++
     build/VS2010/libzstd/libzstd.vcxproj         |  8 ++++
     build/VS2010/zstd/zstd.vcxproj               |  8 ++++
     build/cmake/lib/CMakeLists.txt               |  9 +++++
     10 files changed, 187 insertions(+), 10 deletions(-)
    
    diff --git a/build/VS2008/fullbench/fullbench.vcproj b/build/VS2008/fullbench/fullbench.vcproj
    index 942934561..05ec5ca06 100644
    --- a/build/VS2008/fullbench/fullbench.vcproj
    +++ b/build/VS2008/fullbench/fullbench.vcproj
    @@ -388,6 +388,22 @@
     				RelativePath="..\..\..\tests\fullbench.c"
     				>
     			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
     		
     		
     			
     			
     			
     			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
     			
     		
    diff --git a/build/VS2008/fuzzer/fuzzer.vcproj b/build/VS2008/fuzzer/fuzzer.vcproj
    index f1719e8ac..700dd7ebd 100644
    --- a/build/VS2008/fuzzer/fuzzer.vcproj
    +++ b/build/VS2008/fuzzer/fuzzer.vcproj
    @@ -400,6 +400,22 @@
     				RelativePath="..\..\..\lib\decompress\zstd_decompress.c"
     				>
     			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
     		
     		
     			
     			
     			
     			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
     			
     		
    diff --git a/build/VS2008/zstd/zstd.vcproj b/build/VS2008/zstd/zstd.vcproj
    index 2e2923d55..86dd3a254 100644
    --- a/build/VS2008/zstd/zstd.vcproj
    +++ b/build/VS2008/zstd/zstd.vcproj
    @@ -444,6 +444,22 @@
     				RelativePath="..\..\..\lib\compress\zstdmt_compress.c"
     				>
     			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
     		
     		
     			
    -			
    -			
     			
    @@ -558,6 +570,26 @@
     				RelativePath="..\..\..\lib\compress\zstdmt_compress.h"
     				>
     			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
     		
     	
     	
    diff --git a/build/VS2008/zstdlib/zstdlib.vcproj b/build/VS2008/zstdlib/zstdlib.vcproj
    index ac85f7aeb..ac8f896c3 100644
    --- a/build/VS2008/zstdlib/zstdlib.vcproj
    +++ b/build/VS2008/zstdlib/zstdlib.vcproj
    @@ -388,6 +388,22 @@
     				RelativePath="..\..\..\lib\compress\zstd_compress.c"
     				>
     			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
     			
    @@ -495,11 +511,27 @@
     				>
     			
     			
     			
     			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
    +			
     			
     			
         
         
    +    
    +    
    +    
    +    
         
         
         
    @@ -180,6 +184,10 @@
         
         
         
    +    
    +    
    +    
    +    
         
         
         
    diff --git a/build/VS2010/fuzzer/fuzzer.vcxproj b/build/VS2010/fuzzer/fuzzer.vcxproj
    index 12a4b9313..9f00899da 100644
    --- a/build/VS2010/fuzzer/fuzzer.vcxproj
    +++ b/build/VS2010/fuzzer/fuzzer.vcxproj
    @@ -165,6 +165,10 @@
         
         
         
    +    
    +    
    +    
    +    
         
         
         
    @@ -183,6 +187,10 @@
         
         
         
    +    
    +    
    +    
    +    
         
         
         
    diff --git a/build/VS2010/libzstd-dll/libzstd-dll.vcxproj b/build/VS2010/libzstd-dll/libzstd-dll.vcxproj
    index 364b3bea5..0a4be69df 100644
    --- a/build/VS2010/libzstd-dll/libzstd-dll.vcxproj
    +++ b/build/VS2010/libzstd-dll/libzstd-dll.vcxproj
    @@ -29,6 +29,10 @@
         
         
         
    +    
    +    
    +    
    +    
         
         
         
    @@ -67,6 +71,10 @@
         
         
         
    +    
    +    
    +    
    +    
         
         
       
    diff --git a/build/VS2010/libzstd/libzstd.vcxproj b/build/VS2010/libzstd/libzstd.vcxproj
    index 6087d737c..51b840677 100644
    --- a/build/VS2010/libzstd/libzstd.vcxproj
    +++ b/build/VS2010/libzstd/libzstd.vcxproj
    @@ -29,6 +29,10 @@
         
         
         
    +    
    +    
    +    
    +    
         
         
         
    @@ -67,6 +71,10 @@
         
         
         
    +    
    +    
    +    
    +    
         
         
       
    diff --git a/build/VS2010/zstd/zstd.vcxproj b/build/VS2010/zstd/zstd.vcxproj
    index 438dc6173..90470180d 100644
    --- a/build/VS2010/zstd/zstd.vcxproj
    +++ b/build/VS2010/zstd/zstd.vcxproj
    @@ -30,6 +30,10 @@
         
         
         
    +    
    +    
    +    
    +    
         
         
         
    @@ -60,6 +64,10 @@
         
         
         
    +    
    +    
    +    
    +    
         
         
         
    diff --git a/build/cmake/lib/CMakeLists.txt b/build/cmake/lib/CMakeLists.txt
    index 8371192c5..f4b7e3753 100644
    --- a/build/cmake/lib/CMakeLists.txt
    +++ b/build/cmake/lib/CMakeLists.txt
    @@ -38,6 +38,10 @@ SET(Sources
             ${LIBRARY_DIR}/compress/huf_compress.c
             ${LIBRARY_DIR}/compress/zstd_compress.c
             ${LIBRARY_DIR}/compress/zstdmt_compress.c
    +        ${LIBRARY_DIR}/compress/zstd_fast.c
    +        ${LIBRARY_DIR}/compress/zstd_double_fast.c
    +        ${LIBRARY_DIR}/compress/zstd_lazy.c
    +        ${LIBRARY_DIR}/compress/zstd_opt.c
             ${LIBRARY_DIR}/decompress/huf_decompress.c
             ${LIBRARY_DIR}/decompress/zstd_decompress.c
             ${LIBRARY_DIR}/dictBuilder/cover.c
    @@ -58,6 +62,11 @@ SET(Headers
             ${LIBRARY_DIR}/common/huf.h
             ${LIBRARY_DIR}/common/mem.h
             ${LIBRARY_DIR}/common/zstd_internal.h
    +        ${LIBRARY_DIR}/compress/zstd_compress.h
    +        ${LIBRARY_DIR}/compress/zstd_fast.h
    +        ${LIBRARY_DIR}/compress/zstd_double_fast.h
    +        ${LIBRARY_DIR}/compress/zstd_lazy.h
    +        ${LIBRARY_DIR}/compress/zstd_opt.h
             ${LIBRARY_DIR}/compress/zstdmt_compress.h
             ${LIBRARY_DIR}/dictBuilder/zdict.h
             ${LIBRARY_DIR}/deprecated/zbuff.h)
    
    From 98b85426f1e777b6e607dc1281e292dc00a2f6e5 Mon Sep 17 00:00:00 2001
    From: Stella Lau 
    Date: Tue, 5 Sep 2017 20:41:37 -0700
    Subject: [PATCH 104/248] Fix setting of nextToUpdate at end of ldm matcher
    
    ---
     lib/compress/zstd_compress.c | 5 +++--
     1 file changed, 3 insertions(+), 2 deletions(-)
    
    diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
    index 7863fae0a..bbca6729d 100644
    --- a/lib/compress/zstd_compress.c
    +++ b/lib/compress/zstd_compress.c
    @@ -1030,6 +1030,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
             }
     
             /* ldm space */
    +        /* TODO */
             if (params.ldmParams.enableLdm) {
                 size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
                 size_t const ldmBucketSize =
    @@ -3580,7 +3581,7 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
         ZSTD_ldm_fillFastTables(cctx, anchor);
     
         lastLiterals = blockCompressor(cctx, anchor, iend - anchor);
    -    cctx->nextToUpdate = (U32)(ip - base);
    +    cctx->nextToUpdate = (U32)(iend - base);
     
         /* Restore seqStorePtr->rep */
         for (i = 0; i < ZSTD_REP_NUM; i++)
    @@ -3805,7 +3806,7 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic(
     
         /* Call the block compressor one last time on the last literals */
         lastLiterals = blockCompressor(ctx, anchor, iend - anchor);
    -    ctx->nextToUpdate = (U32)(ip - base);
    +    ctx->nextToUpdate = (U32)(iend - base);
     
         /* Restore seqStorePtr->rep */
         for (i = 0; i < ZSTD_REP_NUM; i++)
    
    From c706de53959eb9e245183f5c39220245600c7ada Mon Sep 17 00:00:00 2001
    From: Stella Lau 
    Date: Tue, 5 Sep 2017 21:11:18 -0700
    Subject: [PATCH 105/248] Rename and add short ldm parameters in cli
    
    ---
     lib/compress/zstd_compress.c | 13 +++++--------
     lib/zstd.h                   |  2 +-
     programs/zstd.1              | 16 ++++++++--------
     programs/zstd.1.md           | 18 +++++++++---------
     programs/zstdcli.c           |  8 ++++----
     5 files changed, 27 insertions(+), 30 deletions(-)
    
    diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
    index bbca6729d..b88d53de5 100644
    --- a/lib/compress/zstd_compress.c
    +++ b/lib/compress/zstd_compress.c
    @@ -342,7 +342,7 @@ size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThre
     
     static size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm)
     {
    -    assert(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX);
    +    ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX);
         params->enableLdm = enableLdm>0;
         params->hashLog = LDM_HASH_LOG;
         params->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
    @@ -3568,8 +3568,6 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx,
                 }
                 ip += rLength;
                 anchor = ip;
    -
    -            continue;   /* faster when present ... (?) */
             }
         }
     
    @@ -3836,12 +3834,11 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCa
         const U32 current = (U32)(istart-base);
         size_t lastLLSize;
         const BYTE* anchor;
    +    U32 const extDict = zc->lowLimit < zc->dictLimit;
         const ZSTD_blockCompressor blockCompressor =
    -        zc->appliedParams.ldmParams.enableLdm ?
    -            (zc->lowLimit < zc->dictLimit ? ZSTD_compressBlock_ldm_extDict :
    -                                            ZSTD_compressBlock_ldm) :
    -            ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy,
    -                                       zc->lowLimit < zc->dictLimit);
    +        zc->appliedParams.ldmParams.enableLdm
    +            ? (extDict ? ZSTD_compressBlock_ldm_extDict : ZSTD_compressBlock_ldm)
    +            : ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict);
     
         if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0;   /* don't even attempt compression below a certain srcSize */
         ZSTD_resetSeqStore(&(zc->seqStore));
    diff --git a/lib/zstd.h b/lib/zstd.h
    index 4879c4a63..662657b23 100644
    --- a/lib/zstd.h
    +++ b/lib/zstd.h
    @@ -979,7 +979,7 @@ typedef enum {
         /* advanced parameters - may not remain available after API update */
         ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize,
                                   * even when referencing into Dictionary content (default:0) */
    -    ZSTD_p_enableLongDistanceMatching,  /* Enable long distance matching.
    +    ZSTD_p_enableLongDistanceMatching=1200,  /* Enable long distance matching.
                                              * This parameter is designed to improve the compression
                                              * ratio for large inputs with long distance matches.
                                              * This increases the memory usage as well as window size.
    diff --git a/programs/zstd.1 b/programs/zstd.1
    index 13c804ae5..0fad1d277 100644
    --- a/programs/zstd.1
    +++ b/programs/zstd.1
    @@ -327,7 +327,7 @@ Determine \fBoverlapSize\fR, amount of data reloaded from previous job\. This pa
     The minimum \fIovlog\fR is 0, and the maximum is 9\. 0 means "no overlap", hence completely independent jobs\. 9 means "full overlap", meaning up to \fBwindowSize\fR is reloaded from previous job\. Reducing \fIovlog\fR by 1 reduces the amount of reload by a factor 2\. Default \fIovlog\fR is 6, which means "reload \fBwindowSize / 8\fR"\. Exception : the maximum compression level (22) has a default \fIovlog\fR of 9\.
     .
     .TP
    -\fBldmHashLog\fR=\fIldmHlog\fR, \fBldmHlog\fR=\fIldmHlog\fR
    +\fBldmHashLog\fR=\fIldmhlog\fR, \fBldmhlog\fR=\fIldmhlog\fR
     Specify the maximum size for a hash table used for long distance matching\.
     .
     .IP
    @@ -337,10 +337,10 @@ This option is ignored unless long distance matching is enabled\.
     Bigger hash tables usually improve compression ratio at the expense of more memory during compression and a decrease in compression speed\.
     .
     .IP
    -The minimum \fIldmHlog\fR is 6 and the maximum is 26 (default: 20)\.
    +The minimum \fIldmhlog\fR is 6 and the maximum is 26 (default: 20)\.
     .
     .TP
    -\fBldmSearchLength\fR=\fIldmSlen\fR, \fBldmSlen\fR=\fIldmSlen\fR
    +\fBldmSearchLength\fR=\fIldmslen\fR, \fBldmSlen\fR=\fIldmslen\fR
     Specify the minimum searched length of a match for long distance matching\.
     .
     .IP
    @@ -350,10 +350,10 @@ This option is ignored unless long distance matching is enabled\.
     Larger/very small values usually decrease compression ratio\.
     .
     .IP
    -The minumum \fIldmSlen\fR is 4 and the maximum is 4096 (default: 64)\.
    +The minumum \fIldmslen\fR is 4 and the maximum is 4096 (default: 64)\.
     .
     .TP
    -\fBldmBucketSizeLog\fR=\fIldmBucketSizeLog\fR
    +\fBldmBucketSizeLog\fR=\fIldmblog\fR, \fBldmblog\fR=\fIldmblog\fR
     Specify the size of each bucket for the hash table used for long distance matching\.
     .
     .IP
    @@ -363,10 +363,10 @@ This option is ignored unless long distance matching is enabled\.
     Larger bucket sizes improve collision resolution but decrease compression speed\.
     .
     .IP
    -The minimum \fIldmBucketSizeLog\fR is 0 and the maximum is 8 (default: 3)\.
    +The minimum \fIldmblog\fR is 0 and the maximum is 8 (default: 3)\.
     .
     .TP
    -\fBldmHashEveryLog\fR=\fIldmHashEveryLog\fR
    +\fBldmHashEveryLog\fR=\fIldmhevery\fR, \fBldmhevery\fR=\fIldmhevery\fR
     Specify the frequency of inserting entries into the long distance matching hash table\.
     .
     .IP
    @@ -376,7 +376,7 @@ This option is ignored unless long distance matching is enabled\.
     Larger values will improve compression speed\. Deviating far from the default value will likely result in a decrease in compression ratio\.
     .
     .IP
    -The default value is \fBwLog \- ldmHlog\fR\.
    +The default value is \fBwlog \- ldmhlog\fR\.
     .
     .SS "\-B#:"
     Select the size of each compression job\. This parameter is available only when multi\-threading is enabled\. Default value is \fB4 * windowSize\fR, which means it varies depending on compression level\. \fB\-B#\fR makes it possible to select a custom value\. Note that job size must respect a minimum value which is enforced transparently\. This minimum is either 1 MB, or \fBoverlapSize\fR, whichever is largest\.
    diff --git a/programs/zstd.1.md b/programs/zstd.1.md
    index 5f6aa4500..2fcedde3c 100644
    --- a/programs/zstd.1.md
    +++ b/programs/zstd.1.md
    @@ -333,7 +333,7 @@ The list of available _options_:
         Default _ovlog_ is 6, which means "reload `windowSize / 8`".
         Exception : the maximum compression level (22) has a default _ovlog_ of 9.
     
    -- `ldmHashLog`=_ldmHlog_, `ldmHlog`=_ldmHlog_:
    +- `ldmHashLog`=_ldmhlog_, `ldmhlog`=_ldmhlog_:
         Specify the maximum size for a hash table used for long distance matching.
     
         This option is ignored unless long distance matching is enabled.
    @@ -341,18 +341,18 @@ The list of available _options_:
         Bigger hash tables usually improve compression ratio at the expense of more
         memory during compression and a decrease in compression speed.
     
    -    The minimum _ldmHlog_ is 6 and the maximum is 26 (default: 20).
    +    The minimum _ldmhlog_ is 6 and the maximum is 26 (default: 20).
     
    -- `ldmSearchLength`=_ldmSlen_, `ldmSlen`=_ldmSlen_:
    +- `ldmSearchLength`=_ldmslen_, `ldmslen`=_ldmslen_:
         Specify the minimum searched length of a match for long distance matching.
     
         This option is ignored unless long distance matching is enabled.
     
         Larger/very small values usually decrease compression ratio.
     
    -    The minumum _ldmSlen_ is 4 and the maximum is 4096 (default: 64).
    +    The minumum _ldmslen_ is 4 and the maximum is 4096 (default: 64).
     
    -- `ldmBucketSizeLog`=_ldmBucketSizeLog_:
    +- `ldmBucketSizeLog`=_ldmblog_, `ldmblog`=_ldmblog_:
         Specify the size of each bucket for the hash table used for long distance
         matching.
     
    @@ -361,9 +361,9 @@ The list of available _options_:
         Larger bucket sizes improve collision resolution but decrease compression
         speed.
     
    -    The minimum _ldmBucketSizeLog_ is 0 and the maximum is 8 (default: 3).
    +    The minimum _ldmblog_ is 0 and the maximum is 8 (default: 3).
     
    -- `ldmHashEveryLog`=_ldmHashEveryLog_:
    +- `ldmHashEveryLog`=_ldmhevery_, `ldmhevery`=_ldmhevery_:
         Specify the frequency of inserting entries into the long distance matching
         hash table.
     
    @@ -372,8 +372,8 @@ The list of available _options_:
         Larger values will improve compression speed. Deviating far from the
         default value will likely result in a decrease in compression ratio.
     
    -    The default value is `wLog - ldmHlog`.
    -
    +    The default value is `wlog - ldmhlog`.
    + 
     ### -B#:
     Select the size of each compression job.
     This parameter is available only when multi-threading is enabled.
    diff --git a/programs/zstdcli.c b/programs/zstdcli.c
    index a60537a0c..a3d508515 100644
    --- a/programs/zstdcli.c
    +++ b/programs/zstdcli.c
    @@ -310,10 +310,10 @@ static unsigned parseCompressionParameters(const char* stringPtr, ZSTD_compressi
             if (longCommandWArg(&stringPtr, "targetLength=") || longCommandWArg(&stringPtr, "tlen=")) { params->targetLength = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
             if (longCommandWArg(&stringPtr, "strategy=") || longCommandWArg(&stringPtr, "strat=")) { params->strategy = (ZSTD_strategy)(readU32FromChar(&stringPtr)); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
             if (longCommandWArg(&stringPtr, "overlapLog=") || longCommandWArg(&stringPtr, "ovlog=")) { g_overlapLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
    -        if (longCommandWArg(&stringPtr, "ldmHashLog=") || longCommandWArg(&stringPtr, "ldmHlog=")) { g_ldmHashLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
    -        if (longCommandWArg(&stringPtr, "ldmSearchLength=") || longCommandWArg(&stringPtr, "ldmSlen=")) { g_ldmMinMatch = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
    -        if (longCommandWArg(&stringPtr, "ldmBucketSizeLog=")) { g_ldmBucketSizeLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
    -        if (longCommandWArg(&stringPtr, "ldmHashEveryLog=")) { g_ldmHashEveryLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
    +        if (longCommandWArg(&stringPtr, "ldmHashLog=") || longCommandWArg(&stringPtr, "ldmhlog=")) { g_ldmHashLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
    +        if (longCommandWArg(&stringPtr, "ldmSearchLength=") || longCommandWArg(&stringPtr, "ldmslen=")) { g_ldmMinMatch = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
    +        if (longCommandWArg(&stringPtr, "ldmBucketSizeLog=") || longCommandWArg(&stringPtr, "ldmblog")) { g_ldmBucketSizeLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
    +        if (longCommandWArg(&stringPtr, "ldmHashEveryLog=") || longCommandWArg(&stringPtr, "ldmhevery")) { g_ldmHashEveryLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
             return 0;
         }
     
    
    From af4068a697f67bebdc100279d55c485271e96ab7 Mon Sep 17 00:00:00 2001
    From: Stella Lau 
    Date: Tue, 5 Sep 2017 22:14:41 -0700
    Subject: [PATCH 106/248] Fix function name in tests/fuzz/regression_driver
    
    ---
     tests/fuzz/regression_driver.c | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/tests/fuzz/regression_driver.c b/tests/fuzz/regression_driver.c
    index 41fdcc940..36ae3884f 100644
    --- a/tests/fuzz/regression_driver.c
    +++ b/tests/fuzz/regression_driver.c
    @@ -39,7 +39,7 @@ int main(int argc, char const **argv) {
         FILE *file;
     
         /* Check that it is a regular file, and that the fileSize is valid */
    -    FUZZ_ASSERT_MSG(UTIL_isRegFile(fileName), fileName);
    +    FUZZ_ASSERT_MSG(UTIL_isRegularFile(fileName), fileName);
         FUZZ_ASSERT_MSG(fileSize <= kMaxFileSize, fileName);
         /* Ensure we have a large enough buffer allocated */
         if (fileSize > bufferSize) {
    
    From 9e4060200b08623fe03daa6f95125d0e575eb0a2 Mon Sep 17 00:00:00 2001
    From: Stella Lau 
    Date: Wed, 6 Sep 2017 08:39:46 -0700
    Subject: [PATCH 107/248] Add tests and fix pointer alignment
    
    ---
     lib/compress/zstd_compress.c | 43 ++++++++++++++++++++++--------------
     lib/zstd.h                   |  8 +++----
     tests/zstreamtest.c          | 12 ++++++++++
     3 files changed, 42 insertions(+), 21 deletions(-)
    
    diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
    index b88d53de5..99d5d7963 100644
    --- a/lib/compress/zstd_compress.c
    +++ b/lib/compress/zstd_compress.c
    @@ -532,7 +532,7 @@ size_t ZSTD_CCtxParam_setParameter(
     
         case ZSTD_p_ldmMinMatch :
             if (value == 0) return 0;
    -        CLAMPCHECK(value, ZSTD_LDM_SEARCHLENGTH_MIN, ZSTD_LDM_SEARCHLENGTH_MAX);
    +        CLAMPCHECK(value, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX);
             params->ldmParams.minMatchLength = value;
             return 0;
     
    @@ -929,7 +929,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
                         0 : params.cParams.windowLog - params.ldmParams.hashLog;
             }
             params.ldmParams.bucketSizeLog =
    -            MIN(params.ldmParams.bucketSizeLog, params.ldmParams.hashLog);
    +                MIN(params.ldmParams.bucketSizeLog, params.ldmParams.hashLog);
             zc->ldmState.hashPower =
                     ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength);
         }
    @@ -949,10 +949,6 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
             size_t const buffInSize = (zbuff==ZSTDb_buffered) ? ((size_t)1 << params.cParams.windowLog) + blockSize : 0;
             void* ptr;
     
    -        size_t const ldmSpace = params.ldmParams.enableLdm ?
    -                ZSTD_ldm_getTableSize(params.ldmParams.hashLog,
    -                                      params.ldmParams.bucketSizeLog) : 0;
    -
             /* Check if workSpace is large enough, alloc a new one if needed */
             {   size_t const entropySpace = sizeof(ZSTD_entropyCTables_t);
                 size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<optState.priceTable + ZSTD_OPT_NUM+1;
             }
     
    -        /* ldm space */
    -        /* TODO */
    +        /* ldm hash table */
    +        /* initialize bucketOffsets table later for pointer alignment */
             if (params.ldmParams.enableLdm) {
                 size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
    -            size_t const ldmBucketSize =
    -                    ((size_t)1) << (params.ldmParams.hashLog - params.ldmParams.bucketSizeLog);
    -            memset(ptr, 0, ldmSpace);
    +            memset(ptr, 0, ldmHSize * sizeof(ldmEntry_t));
                 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
                 zc->ldmState.hashTable = (ldmEntry_t*)ptr;
                 ptr = zc->ldmState.hashTable + ldmHSize;
    -            zc->ldmState.bucketOffsets = (BYTE*)ptr;
    -            ptr = zc->ldmState.bucketOffsets + ldmBucketSize;
             }
     
             /* table Space */
    @@ -1060,6 +1055,17 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
             zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
             ptr = zc->seqStore.litStart + blockSize;
     
    +        /* ldm bucketOffsets table */
    +        if (params.ldmParams.enableLdm) {
    +            size_t const ldmBucketSize =
    +                  ((size_t)1) << (params.ldmParams.hashLog -
    +                                  params.ldmParams.bucketSizeLog);
    +            assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
    +            memset(ptr, 0, ldmBucketSize);
    +            zc->ldmState.bucketOffsets = (BYTE*)ptr;
    +            ptr = zc->ldmState.bucketOffsets + ldmBucketSize;
    +        }
    +
             /* buffers */
             zc->inBuffSize = buffInSize;
             zc->inBuff = (char*)ptr;
    @@ -3159,11 +3165,12 @@ static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int
     
     /** ZSTD_ldm_getSmallHash() :
      *  numBits should be <= 32
    - *  @return : the most significant numBits of value */
    + *  If numBits==0, returns 0.
    + *  @return : the most significant numBits of value. */
     static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits)
     {
         assert(numBits <= 32);
    -    return (U32)(value >> (64 - numBits));
    +    return numBits == 0 ? 0 : (U32)(value >> (64 - numBits));
     }
     
     /** ZSTD_ldm_getChecksum() :
    @@ -3183,6 +3190,7 @@ static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard)
      *  numTagBits bits. */
     static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits)
     {
    +    assert(numTagBits <= 32 && hbits <= 32);
         if (32 - hbits < numTagBits) {
             return hash & ((1 << numTagBits) - 1);
         } else {
    @@ -3221,7 +3229,8 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
      *  of rollingHash. The checksum is the next 32 most significant bits, followed
      *  by ldmParams.hashEveryLog bits that make up the tag. */
     static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
    -                                             U64 rollingHash, U32 hBits,
    +                                             U64 const rollingHash,
    +                                             U32 const hBits,
                                                  U32 const offset,
                                                  ldmParams_t const ldmParams)
     {
    @@ -3272,7 +3281,7 @@ static U64 ZSTD_ldm_ipow(U64 base, U64 exp)
     }
     
     static U64 ZSTD_ldm_getHashPower(U32 minMatchLength) {
    -    assert(minMatchLength >= ZSTD_LDM_SEARCHLENGTH_MIN);
    +    assert(minMatchLength >= ZSTD_LDM_MINMATCH_MIN);
         return ZSTD_ldm_ipow(prime8bytes, minMatchLength - 1);
     }
     
    diff --git a/lib/zstd.h b/lib/zstd.h
    index 662657b23..794a855a4 100644
    --- a/lib/zstd.h
    +++ b/lib/zstd.h
    @@ -390,8 +390,8 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void);   /*!< recommended size for output
     #define ZSTD_SEARCHLENGTH_MIN   3   /* only for ZSTD_btopt, other strategies are limited to 4 */
     #define ZSTD_TARGETLENGTH_MIN   4
     #define ZSTD_TARGETLENGTH_MAX 999
    -#define ZSTD_LDM_SEARCHLENGTH_MIN 4
    -#define ZSTD_LDM_SEARCHLENGTH_MAX 4096
    +#define ZSTD_LDM_MINMATCH_MIN 4
    +#define ZSTD_LDM_MINMATCH_MAX 4096
     #define ZSTD_LDM_BUCKETSIZELOG_MAX 8
     
     #define ZSTD_FRAMEHEADERSIZE_MAX 18    /* for static allocation */
    @@ -996,8 +996,8 @@ typedef enum {
                               * (default: 20). */
         ZSTD_p_ldmMinMatch,  /* Minimum size of searched matches for long distance matcher.
                               * Larger/too small values usually decrease compression ratio.
    -                          * Must be clamped between ZSTD_LDM_SEARCHLENGTH_MIN
    -                          * and ZSTD_LDM_SEARCHLENGTH_MAX (default: 64). */
    +                          * Must be clamped between ZSTD_LDM_MINMATCH_MIN
    +                          * and ZSTD_LDM_MINMATCH_MAX (default: 64). */
         ZSTD_p_ldmBucketSizeLog,  /* Log size of each bucket in the LDM hash table for collision resolution.
                                    * Larger values usually improve collision resolution but may decrease
                                    * compression speed.
    diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c
    index 76495d453..1a9aa5064 100644
    --- a/tests/zstreamtest.c
    +++ b/tests/zstreamtest.c
    @@ -709,6 +709,13 @@ static size_t FUZ_randomLength(U32* seed, U32 maxLog)
     
     #define MIN(a,b)   ( (a) < (b) ? (a) : (b) )
     
    +/* Return value in range minVal <= v <= maxVal */
    +static U32 FUZ_randomClampedLength(U32* seed, U32 minVal, U32 maxVal)
    +{
    +    U32 const mod = maxVal < minVal ? 1 : (maxVal + 1) - minVal;
    +    return (U32)((FUZ_rand(seed) % mod) + minVal);
    +}
    +
     #define CHECK(cond, ...) {                                   \
         if (cond) {                                              \
             DISPLAY("Error => ");                                \
    @@ -1380,7 +1387,12 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
                     if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_minMatch, cParams.searchLength, useOpaqueAPI) );
                     if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_targetLength, cParams.targetLength, useOpaqueAPI) );
     
    +                /* mess with long distance matching parameters */
                     if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_enableLongDistanceMatching, FUZ_rand(&lseed) & 63, useOpaqueAPI) );
    +                if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashLog, FUZ_randomClampedLength(&lseed, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX), useOpaqueAPI) );
    +                if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmMinMatch, FUZ_randomClampedLength(&lseed, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX), useOpaqueAPI) );
    +                if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmBucketSizeLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_LDM_BUCKETSIZELOG_MAX), useOpaqueAPI) );
    +                if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashEveryLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN), useOpaqueAPI) );
     
                     /* unconditionally set, to be sync with decoder */
                     /* mess with frame parameters */
    
    From 8c33cfe0bc167274415f711643ce39cc02c0848f Mon Sep 17 00:00:00 2001
    From: Stella Lau 
    Date: Wed, 6 Sep 2017 11:03:35 -0700
    Subject: [PATCH 108/248] Add ldm documentation in README
    
    ---
     doc/images/ldmCspeed.png | Bin 0 -> 72251 bytes
     doc/images/ldmDspeed.png | Bin 0 -> 27594 bytes
     programs/README.md       |  58 +++++++++++++++++++++++++++++++++++++++
     programs/zstdcli.c       |   2 +-
     4 files changed, 59 insertions(+), 1 deletion(-)
     create mode 100644 doc/images/ldmCspeed.png
     create mode 100644 doc/images/ldmDspeed.png
    
    diff --git a/doc/images/ldmCspeed.png b/doc/images/ldmCspeed.png
    new file mode 100644
    index 0000000000000000000000000000000000000000..d3bfce4c80123bc9bd6ef8f46c76fe79065defa8
    GIT binary patch
    literal 72251
    zcmeAS@N?(olHy`uVBq!ia0y~yU{hjXU|z|=#=yWZJ=dO{fq{XsILO_JVcj{ImkbOH
    zoCO|{#S9GMLLkhTKL1h>1A_yDr;B4q1>>8$l_fFPYt?_qJ22b{pD1$F^@`WTNjk1U
    zcQz(z=Xy^wKic;u(>?3E#of6YGr!4qUOqm#EZcL+6NApl*DPy=ewU;votn9^*2cI~
    z_;zk|P|j-An}Ji7rDjdv(JfRibjMLhfg|Bwt%D;2rwErfW9W+W-lsyp-m5+RH%4jU
    z&!c1qXD7gmdG%b?fTa+}@HId|e{$@=|PyAlmja
    z@wWP}4qK~L^TiL{7>EiM4gra&2cDgs{rU52_fk=HVYo0lql<$>sq2A-3odhd{2T-f
    zt?birn&8U9BIsHmqlDohs7-F_3LO%2=Wpi3;%AVOMkS`E4kZgdK@bO9*en(naOpXB
    z{wCH?Q*dZ-5M*?85tM1i6<&=OIXRTvo5DF8;KfjVtaoloUENnjQ<_vcSNK(ecQOKXZI>#gd4i
    zfQ!h%!VX*(NX%_eNGhp2r-mz*MtCyNa#*l>^=hVhhm-{r3??`ncCdb{j4h}fRJoTt
    zcz82?ey{xB7w#K#Z*Q|GeHC(MzP+Pq9lQd<=Wb4aeup?DJCW+M?O70y?EnB!?HIw
    z1YciY-~W7mz1_bb{r`XLF<7*Dv$0&|lZk)!d^w>VzV6KV`j1D&AGeCfb=3a;c67P@
    z-!tVqy}keL`uF{IzcS>UbYgZG$klu}xZ^<+_ov6v+w*$ue=WA}IxbhO
    zvu@w7S36!VoBeC54vbH^7B&4?ct+U=&;`_7Ur
    zeE022u>aHDcAsaS|I#Lq=^l0NWuNuC6aBWI&lvyQ{a?W$;SCFmU~>9PFHiNhtxtEZixC%Za){kv+7|9{Sv?=!Byzai0ij&1d~
    zJ&(%-6byL{fIc>h*DgG(EHgfZ_`;+(nd^Y>%_t4d0M;#Q8U0Uk>
    z`EUBUIi1PJ`@ULV7iVH|Qx7OKRWi%JXR}KVYrb#f6!-Z5z&jw!Z+2k3p_Tf2JN0UZCahT`P|#r%9&W&)B^$?
    zTLh9SnwOhmmK%*;A|BofORrbo|9x+h-M#yN&fY)5U;pE9Ms{}hw{PG6#O?pUysv=P#$o#n#T|V6+bwUifa_+62-|9@x?O4`-(iv>cK+!Suk<>kHmKjzlWo0bv6zc~dY
    z8Xa8O1eIU32V*PQR~R-%=kGPWw0gtaJ3Ec{{duZ?e3|d;q_?-WeoU|bmcG|m`O+ru
    zOzYBDAq#(2zF%qQa_iZ-xz+a!tvLiFb~YqkRo-5#h8b*(Ork0ql8$!$xbxgjJoD$$
    zkk=1iE}#Fdc30%)w5Rj^=h@ucz5ac>33t*8E1}xkzkM1UUNSXxTw1$D1w9E0C^#%Q
    z#2WOV;N{Zk&-{1h-`{s{`CRk-xPO+qw@ogTJvh)<)45zEi6`tr)q>A&lpPW>7#)vX
    zaEroLO9r?yx%bJOoL_cwlImXn+PkIKk517HR%#Xg{r&y>yYW9hT%P~W^BVv5}#1qhP?AsvMcv
    zRxGtnW1)~m;Ukxt@4N5!y35y^fJ%jkT_u@vHaYkA*>20ZIm!O$-12)jce?~X-1u(S
    z>vcDFm1f)g|MR)<{oe1-o^RW>?bxrcuOEMTdHLhV{(76R^>MKo@8&Wz8VU)x^aw6F
    zjV+iA?3h-v9a;bH)%s(gq+aoKYWSz{hv!aD*YEeQ`!xCEx$=FRH?00{E4umL-uu7z
    zR{VI_uG}hSUH8lZeL?(VmStC_LNOqhpk<7z=Ctn|G)41zhq@*
    zb{=l$f8KbgRXk3@*Vor|zQWmg6(0_=FJ8P@IsQ=Q!6sJ2D%Ye~BaI_W}tp-Qi0iz9}(U#z7
    zQ+Tv50PdP#4i}8%&QQW9j*`++-+AX=a5j3XT`)NLYq2%92IZ9o2QImJ)$evz{Cc@O
    z`Sdj1isd|6R@4
    zf77$!zzJ3sL0khX!YUi`?(VAibW;8E?(_3(t)HElDa_6%b0S`ILB#H|T%GuRd+uM(
    zy|>45Tkh>^`SJJlpKp6#eI}iW#Z6D4Lt^J#V{8)$GZY%cv9P&}_}u)$zU6@AsA;SibxDyy{1`?<>z&9+#5(Q~a`0qf9`8nbAHn
    zx#5Knwh-xAf1vjJUGdAyd|#JezPdX6xVzn_i9e2+?-R`Y<{Y(e<+^q2;%9$RW##kr
    z^?m+!dox4hCk~CUSh?_URV=;c1wBm9+XPypMbq53Y~AYW?(Uwry_|_fEx!Qd1^n(G@3_&b+imQ<{+}S^YtJ)*GGJ&W8Ew^=uqH
    za~tL_-?+I%mC5tK`6>47EXVu~oWFb{a+gqJr@)Vs{&kb?e_J*?PwLCJ|6lz7i_A95
    zJ=NTGv|If6rKR4Ff4yGc|Ep^Mc3X{E%q(t-0TUgMX#9E{f^9}4E9Ak}>v7#*yc!R&
    z+y6NDS%j-pF|O+6($9TsBQ`44JvOgX290)q?z`y-8uZXI>WJ8yb@fHn(;Oz2qQ*n{
    zAAijJ#NKq^1?wN1-g_5BIYe0g*odm^5tfi&zgdUSTb^QdLAF|KQ5iWNAUi?Z`+ff
    zpPTzJ{{QRxUj3Sf+=kiL)_gvtgM&hxc;^WPfGIqucE_WsAd@+ZsR+}N0G
    zu{_JW!GV*hsY7Uji6W*W9Tpg|{(JZSpPpR(pN}SBujg72Yn-MTXPM!{iTbC=lI*u?UZ($c3#
    zS6!au^D@f(UPbbILwODX328>hBR4E|aba5C$SIg%cTJ3cO||W|x0W~G|C7F-)%m5W
    z=5J#}_4!#57Tc>|F0AWa^~F0oJKN^d3FV)cmor^?eQmAu2KDPP#lClHzu*12F?M&^
    zQD=VJDdMZ*HmCXitNZli;GOq{Oa(Q%*&6i*S)>|>H5KD
    z_Qyv$g)0+Zw{nZS)&6}Fy(=riLP}U;bHn@%M$Efyu!L_B=aN|hOY;tAM!zy$y){-V
    zYi^o{PTZadj=;6eFLti>au5g%J^VBgOKH4EH$cPZ@3(me?Rl5KeGp#Q!obLMSX{t`
    z=l&T;I_@6|jkws7?H
    z9!UQG*dG%@&%cAt(-S>Ctt&1|;{o$%L$o3cq0mFyR4;WFkfeo6XcA;*Y
    z@xJeG_EjVuK6qo}`;a*&_dS1Yl)72*QcH*Qx;g4C8ofcrrFr`s3Sd)z9yAF_TvMn?KE^=0&`Y-SZjiSvUk{R4|HWsnzk=Fk(qei#SRX3JwV-pegqkmeavO0ZM6b#sLeCC5Ns+Q}|X;%x8e+_b(RfVY&n&
    z5)k4b5IE(yBbG8)O7yIe{AKl$JG8)ZK)
    z%>)&*U8aRS42(>VLG7dRB6BQLPzGBZqO0Bi9Q?o4ux``Gj4M}{vMkd6egEL$4iTp{
    zd((YQ%pzD)Gh%f)1SI?!9gkFG?G}gl7`fhQ6k_q4XD7{X^C@c2r(>OVYhNcl+;i;5
    zf%AHOywQC}`)ZeeN?xhv64j@9wnf0{%fn9-85+9;1zbYT1XKuM2{J);Usugq_-O%V
    z7Qd=@p=OP)T*UXPoZFY{Z!Yc4-|AAewCYOW^#AVnu9mNxC(i$G_f^BKgHUKVJJkE%eIukBt+F6mn#F7>3AQ1Svp6SbcL{f%2G~o=3*D7YiwDMxmYMGGs
    z1~2oghJN!VVJKX{#nN@PQKQhv<=$!UX=he6-K%n8V&RygrqH2r)>9k9`HW1?Ts9jY
    zK6sG3X&3*}yzO^)thllaR1z$B#L6NlYVRTksz6Yqa6uGH*VVEU#T`P2I!;eN*JGU*
    z7o;2eZ4PMlRFH#!p~^%yR1M%P?WR9LeAT+slRA_VT_81ql=Pp?cV8ThZDeTl5)4?g
    zE6D9ou>f+UfPELT_dwUt%gLwLO?LeiIQ^+W?8HwUnZe7yZ1Xl%yj0|qsn#N}X!=oh
    zCKk2M28EFVsPbfpoM$Sr(+*~oZVlc*|%+rcx=_m4+~y7h^XulRtVr`N^`k#NaHnT
    zj&Zoj^6z+C^T!MScdOpA-lRJH)vHavmsknhto~(jU>V;L28}X71%s8WEP|7(DoXpn
    zK1Fu-f;mj_zyF>4vH$aL)3ro1sUsab5HfJW-jELyq<;QN>78r
    zqO`Uscg*^?P5T0@CR3XI^@4do#ryL*J!h?>AJyC3ueqmM|Fl{A(PjA^7We<}|8qL^
    zx$O3421cf>Y6=}IwhCU4$4D!UlUQc;Z#~NVI<7yr+V5NT{*P;?d92^U6ny3B|B3SX
    zbArVG|GpcZwpmf^Yxa9k{e&k$Kd=Gk+xGbGx7E9+hgz+7yftxp^NQ1-I@ZlF-fZ~q
    z!~ON0+4{4M6N0Td1r!2KGc|QY$<@|kDF6Z#bdQIav}nwk+A8>Ylfa|%^{;nDY%8cr
    zTwf0I!3*Vp`_DJ`V@Z%4DNHNXTvpzG^fS0sU};jOdxL{7*9^hH$%ofn##G)cx@e#7
    z>W={$KCxYw&M`0d&RoXJ$i#wkKDY6fsKh3L(zlmhSTZuP90N5to-NVyKqM?^ln0z-
    zQWafvjw_%%e6idv_31h@4NH`DIRrq3UY5(14-Z~jp{L0OVys?TE^~`Igtl*)GPxII
    z5SzGxa#De`J2=UL1mFy{i4L!4_T8x8p}X(znR|-WQ_r_+BnE-naK~iL^(8-5Nr9%t
    zr?IjKZngRK3u7p3h6|JI+}MjXTXet4<@MIKbG=`C^ZT|N)8ASbEwX)|8y+5h@#FBrA^whqK%qN?HH<85lsZft
    zMPX^aW1#A=d+9FD%#({uq7!ufFZ>tbUG0BiLMw0NfeqgSxTJR3zqh|6HFxgf*WUj(
    zzh1O*qu#rnk0%wrjQ(H!8&pD{R95JiVUxU49X;wA3&l}-KKI}~pPFk24($y7Ei3=V
    zJIYRzmFM@S2F0^UFZiT(rJF1{zc$@%z6p<^S3(-uKvf?8~e6bi@DrSZauHLz{ByVxP5i3ow1Vc{1Ss`JIz*}=X&#}
    zG_@_h+0$N>`}HQ5SNC(@-nL)6Zd|<+btzY5kzS{#G7}4jh^T;z$kRfMA~+zD>G4jU
    zO98h2rwv896}g@-H+W?J@AT(FGj2t`6vZPq^yY``@c#aLPh@Z5#io^o7g;YSd4AiK
    z;aD|a%6rpy*GLXSRc^&e5A*;1^nQN!(Tn<}9IY$Pi+-HTz{sQwS~q&;Y$TR&lz5#w
    z!Rw`i)|)#;yOjIp=JbcmSFE?MH2eSOto(b;r$UvpW6v(%{QVK@BJZ6ywk-QKuRyVt
    z$F|W~&Mc+T`CDz&C|zdO)eN3y%-L?UBDVzBX6a{X#&XA!yiK()6$L&HO{vzIcheM<%hobAb!5p}
    zo<|=@>e+eVX5YFWVc(+v`R7E7Qo>to{Yp~?$GKTng7CtqLqtnU0?aAAA=y8MahpFQ_`
    z#`mpN=63X(V>g?f?YRHkUg4YCt?Vz0tLkh1{+pEl+kd@WSH;$rm+Y$Xg%8@6o+;3n
    zGqY*p{r~0Jj}8e<_t%>992C_otKuC50{l0T$a5*7)}s9Xnatp%
    zcV~{hxhjyEx#Y{N>9zMOAC&yLyt@5-uHA$0@m1elHyX{3O#-!!8gB^;xLmn6=Tyh9!Ke}6sOk@ND*y_sCK&aJ|>3!T!#_!kCkU&G>jMze+MrEM#h
    zW{k$0*FWccJA1OJ{mVUr)CUh#SuOVee6H_Wq`7VBq4SxU+Mtdn$CYIb3X9B+$F4`M
    zFdck3=j6Sfx$uIp$dV5WK6rV{*Zx;us$c!(OZVB2U%GEza(}#sH(hcGYw@f{=f1~W
    zk=09abegr-pghcMwqo^s+reZM*ux%Y6dw
    zGBtI)lC$^sN38|gbSKnx+n!}uairyF_Ok=D+bZ!0c5
    z7cn_A>z+XIrUeT1Ut8E(&)?o0$!=e@atp(g;O)BSyA8zG#h&{fVyvti9@<;K?9|Ig
    zw?MJ_VOxX3qg?L!pkfPQ?SUnrLecC&{`&rK$7d{aoEoRiljJbZ=WuE-$Z{l|6&pCDMQo1Y`)UajuPNV6L
    zUYlj#?MZ#Pqg6iiWBUPTP=am~b?`~N>=Z>)X4($P99%kf!B
    zW69n_XPUpnY3!Qw{xoyjmiK=aB(7L=rr9n=l3(QK_y3>YS=mRwdf{we{;<-~iA$Pm
    z;h_Xm(Q~_R7?ee@WlBWM0^8>b>K$iU*zlkxCXM+HQC7<%I0APRb1DBj{eQEiUcA|A
    z^NbgKB2`YU^Cm3(>XZI(N>_dUsk-F-)of1ReOkWk{5`dm{pR!B-O-O$3ca@bGy8V9
    z&yDQAgM)w}Lsu*)oDn^f1Qn*KA=L{PFV^ncGN)5n{nq0TAB_tw
    zs{j9=cPF-J`@EWkmh);BZmD8XjW6MmTBh31rRc;Z@ag=`Np7{yt%p7y`aNgOH772m
    zuH4Kw+ur^1d}CFzEn>4r>-6_KDm^cnJ+;e_TvEin+YaQ#o~;cENo!nV`@zK}tO1!7
    zl&~jDe@>3Aw0qz7;|ql&Ph1c-C}HQlyYTSBoOmwzzPUN}>*qPCilq3}TU;{oFkZgY
    zVd3&TC&hplweROGosgv_a;W9YylHl`j8v_6@Nd2JigxCf4sb%
    z)tQBBFQaq$27~M<=PTEzs|QFFG^IB9nkQ`ZwNKRiKCk!ASb1UkG^hCiiD_aQKHJtR&Mqu`uIsJ7hV4ko=PUAH
    zQzx*f-M=r*S{{sOP@A;(k
    zPB^vyjC?Vn@BI9$C2_W`TUxGw>i3Pg=TCnAb)no{RV3xzZyP)4!ojP$3LPunef<0d
    zCGi?`9JtwcuIA+8eFvQseLzj2=GHCmkG$O69FzK|?EBok6WDn(#hk@-VkVqT@p#X@
    z>AT79M3d8sOMkJgyzz
    zzoz=wp@f4@vu+mrdGe!``|!%W8#3-)`7xD0ZVo&5(KP)j**nC}&6SG(^QLs-t0;{V
    zF?y-jp>ssPxHy!4W&Q9$6ln~NQUV^QKZjhhcPd|2@bJpbnwyK04mw$t>2NFV+ND-D
    zA;|FYPUFpyT$yc7{%>2G-ESuyo^~lq|IXKasUIKC-(BEjJu%Hqa7#@
    zr_b-7|1$iEWv%_Jt7#`Tb#UH&^;(%+ym*l6LT(<9P_n$xM)KP4{Rs0;JoS2M<9c}4N8l^@C`KG(@O(QUQeJ<2Up
    zY5SI#AiLtkuvHr;?A`R}?8>-azv?U#FgXIpY@h^M)U=l=nheq2opK
    zLzJHEG4BMWY3^Q-HfF7V;*s}upQ2(c>Z9ZgM5cLry?-k!EUmXBeU9zohi`vz-Rx#^j@B_ZXCSA#9)q-m#|mS1}PzRlL%DZA$9+0EK2yTAU(eA8O5`3i{-5)}C*H{Ik3
    z-Xz64b=S(h0V|as?*u0|hQ>}20T-Vo`>LU-92BGh#Y~H1@qsrfuZQ*QBJI-Mr=x)ZM$
    zXFq%!#dCMF1X~o_s{fZkT@Gj##?pXv2<75QuUryxKJnn3Wi^#coDNLja^T;?8}~i&
    z!8hgG)@xVV@eA*o?j&Us;o;~U{P?G-np;_TI(#cv$mRxxMYG(`Z$|b-DAURlpUXE}
    z@h;6fpD%m+>BKhU!-*I7to*q0_Ox_ksZEmHH+|YfI+iq@ySzD)&kS66fs4e$f&wl)
    z?%vS|5f%;}#R-Sn?w(z{QN8+Yo}KJ&{Qhitz-8^Ur%Rg
    z=E+=mS=E(hzwu$hn;X|-pZuDnYW!%MwD?nF#TEh8;w%qXQ4-M9psP-Jq~2%I#D!sOiH1
    zHbTK*g~QTT-e$XuvICzyj+V%Pn%H2O89kuAOctwtA(rMR2yyX$Sc4x+MDe
    zjPDk@i$ikK4rk
    z{>nA;oEvk`XIRJz8*WatIn=gLM+PzO6Tl4`3X({zMU2}Ua3RK${CTUUiUcfK@ThzK
    zUcL2=1{V{Z7Y1zEka$6{7#8vl4F`5`awr|^z152d{E+1iQGF{TI09dUaw*q6?XQz7kliLn=3il2&z%jVw4&K^@jcPEm`?_ayuOo&T$9?;LeVbJ4md
    z-=3T4h;+p5D~JlysH)1*Nh@v1A)C_p_@bd>mLO&<2VYXZGY=p!+
    zvnxF9`>yX!Iob0=fBsIhXXo=??Y^Ck(9Dt*;UExrxOx3+xbCak1@GRp)l73XJDj*C
    z-F%5a(zPvZ7KOXENDA+-_$;L8^7Y@wPfy^=Sx$kraB{EiMkHYg>Bd8E+P3q}soLG<
    zylqO*s=Ef0Zt^zUhDLd19$oZuW6j4eJ1nY~e*aUwO}|wTR!*>6+upASP4Kvjx!eFp
    z6*LWA2zL;;7=9SZ)xrt}^EOM1ou4hG9dzP?u*sSo2HdinHY7g0v(mMC-?w?D9}n!h
    z4sPd8yk%l`MSO2xGs3+bSLQV+Ec$jVrXSvYRP$IMlxA*X+NYxd9q6fff3x=Ek+$ZI
    z$@f>r7+!4wP4NHp;ZQun^7mj7QaLQDr_izD1LLO(xcSNY7wWcc&iTI}j(4-Po7SwR
    zHtYPzS^M3pc%LImT!nyYrlyWt(#5v0`t!;bhtC_gF;17b^&`xC$@Ryt`JZ_6@NNyc
    zxO21gy;HBu-kj=k?RS6M7IHZ8=AoB{mu~W!{$+P~4)+3wfJ8Z?Lv^XqgJ|p&_4vvQnv!4cop|JK{RTU~Iqyy!?l|=C
    z;y(ZRR;pnstqZx2E}EX+*nE?BacC*H!vk%CPX&eC7r{?8h>%m8(4{kdm#lrMS@ta7
    zP>E;L(#&Hl>a&*I$vvErZM6=qnPZd78Dm5rU4
    zX0d0_--w)hH-na>{&&udTqdH$v+eAOH1jXK(r5A{d`{KDG=PSH(Wh+;PO=2acIfW*
    zKjwYA@962)}z-i?%Y}_vPm6#Va?~E%3gHx;s@BR5P|*
    z>Vc+zhXqC~e%nir9NX@fVl21mCg069?bq+y2)@1f$y+sdW#q)C(|*N0R<a0SR>s}vjzI}3nAKw@EoLQ+eCAG|)1kZ+v4HvREdS;_q!R
    z0L>%D9oSW#KA&H+1yqS-sjGmz@XwEc5>#756)zW^?B3;r7>?mrfH)@z%cyG6C#15MzNAs5VEM
    zJ`6Brs-ESa-gx+ap@Q_q)qur3S!
    zU{Jhk|1v)AK)6wjFJ8Us+Vv$`*Nllp%kMz_;nh17KRQ5t+IULz#hW*$x~;{V+D#rm
    zym4~#;i?Ckksk^^E^7O+Gh6S>q4u4HZmY@$G?i8OtdfDGz
    zHhNo5=d@|lBDQ1%#uOeEExaCE{&YTjkk|9S57_NHrpHxj+UsxK`RCK=$8FMi9k=uM
    z*DeSKZ7-d|)YK8kWCg3e4Q8@hZF-P+``zTq+;$N=P${ux&O3>)>C)1#lFlC8ym{%g
    zXHQDyW}SQ2zbxnes?g~?udSru4K{%n+8bbtIb%1cpYO9Qes-jhnf+5Zm&UbqvC^lf
    z>%Xt|Dk&>Frrd9HsrufjsoIMdE>w)G`FOPAVXJu3{e86`U;5YYx^KBpK*692bhrU;
    zY$G)78Dz4YD=RtnEY|j*v)S#3Q_cO3yxjJXmH+arSIK8j-Q0V0>E-9g+H#~^&Tp&y
    z+<3_SJtCakbT$+}KeyxQwCG34^1mZ=qPOYnKXlen-Ri|GK*4`@QPl
    zvHvf+%b#`bXyq0^*354wAs$oUSXcA<+S-rq^Nz
    z&sJ!EpF==mA7WYQqgPi~KUS9i=~44o`hLgR+2-@Z%^$5?KJV1+`e(-TU-Bwm>f18s
    zvTXSs!TSH->*deeeC|p@soY}lHL3f)1X*pX{r&C6=5+rhsdIu7
    z3g3ML?UUzMGRwIkkbZvNTif?{%JvB>7}PX&@hAmFWrBB#|MBUayHs27!{;aG9kz1L
    zvAZmJ`}^G9wbkd3OxyeRT0`1R2@FG~xLPCB;Z(V}HLiZYXRVhvPZy$bqJ
    zVD#wA$rEWC`!ha&Hc>KD7nBG&aQ?~y6FvcnZ4L96Cr-9(ba3SaErqS07haB}GsvENF~=hg9^V8d7CN~8+kR?_*DVeKiMAiPJl;cO`r}PCutbNi50i!*y4VeqR1;tL(b-(;};mKP^tW
    zdFbWgea8y?K72Nj(aq)L(S4Afm7%Q5F-7aa^OYf*Z#j5$Cropg)$ta*`gYa&_5J*H
    zADaKlDV{Czxc%j2^Z(lID_3gfPj2D>uMGw*;k{9Mek!P-1eKVRy%+q9h?cWiBE_$t
    zcJOfYZ-4&X&8Nluy34;@Dff8j%%zlr$VjVV7r<8B-u>~y-CjyOzNT=$-q!8gpWolz
    z@17KAVmT)&;4(-1ku|i*mB7P#>wMX<@AK}8LuZ`Mhk<6CK&?m6
    zx}`-M7w&s;mro}1G;_PjZN*mp-Ls>+x5>YFa8%r{zh;}W|Br%$bKc$mB(-8~Es~Q0
    z6!nwEl-}~2D^(*_xQc(`ww=Y#pS}Or4BDG6;L_8(
    zcr~<{#d1#AW3xD@g3Y--S+w-s=G>aqs+V4W{K}s6);2ro;hpX2DsM9FWc71j&wKkJ
    zNX%x5LXt)FD#hANv67hSXG?bIMW?;ob^6({JCVJIceZRpa+V)_O>fY_m*;EW6;FI+
    zJ7@RVS*F_eOFyOj-#=gc)>4Dy6;?v6+wO4+NX%kofC{a$V0o?VYCnL+`$r#-%lB7)es&bJE?9$w@A)?!S^wMXVt1djol)_=LBg1h4BFuk%~7Pk1MeXX5L)-`~7}+$pTAAXs-zD70v(8_)LcBkD2t%|*U|6f_%Ki%zjg1%Vs
    z2`L!VFghOjaCQ#tv;+(P1&bGJ-@8$6wEpjhU$fPdg2R{>U0J*O^;=FsL_HLqK7V$b
    zMn>$b+AZ+rq=G>tOH_39a|xF=pxmO9ACse
    z>hI@eWOVfP^;uMX$@ur`{-WQvcW#vnTN5F;|9ka*aen(h1)#$j%HG|X`G0Ti&reT3
    z?)$!1-|ovoe%=zv-y8xGOB)oDrZo6L3sbfI2VQRLyRm7tb%Dph!`YFEFAuBV>Mq-J
    zghy%ru~nj*AH9p7F1~jja-VaLu0iduFF#)I|Mz-(InU$Epq&Q?+2zkT_w23yeyoX=
    zJLy=D=~O%D`xH*PVU
    z{jor6HlyLB+<$M5?b+w7rB{3OljO(n`<2G`Zd9*&u~aYK$`~}We$k9i2$rh^6bvj`
    z&&{)yzW?`K`D5$*KmFnsFUr^Nm$#SOUH<-Dx$UnPi$A_A-)~*_b9%j{nC_=;pW3-K
    z>-ZQQT}pc5upS|E_<3{k%zV
    z^1C}b3!j~tnUR_K()QaKUb!V}
    zm0~O#l=yP(ZvSI9`yQ^_c%}ArYWFhNSuZCzwO_qi%_X?ZM|0n|ONVv_KL!nGAyy@?
    zuP!^H>YWB#KH8I!F&8ngx8N0P(25CZPD^xIxwqf1tNwFH|Bus>r!!tvb)8#kko5W4
    z*@1obuqU=^z&s;iBl7I8E{x|D=p`(-8F8q&Gka`DdOAjRX+ls};#!lqQ
    zzh8d8w(#ZB>GQ6iU$$%+=(Lp2*Fh(#)JQJ>`uh5FW96{*akX*P)*K9xapeNxis>pPrJ$E#Gi{^D({+x
    zGUO1j>cF|V)}NQ{|IxkQB7vjuUFo}hzu(>1kmw9L)97Bs<6ck&{G?hHG>TSPVgp_u
    zAfPY-G{tk;seRhKq)VV8EN0i*y~Qq8-Ov5cPK&6rF4<9ZbWKLk;zXBeen`i+C8RKA
    zo?QC(_xI=O>!Y@=TGD;x`t{?X;jvTM1+B~8XuOo^)xKq&tCi9
    zG_i7j+Q!Z&qw!OQmoo%3t}Nts&=^#`Ff>Yudc0ov&ZfX>_R9%P?eA{!<-f6%oU6P-
    zJ$C-p-hDp~N!lJ=vb(u`>do)JN)EVz8a&WCx{*uBv>l-#(n`O2k}*ZKs%)*O6u
    zY{#odH*Hy$rXLN}PCNc3hph#?W(}5~t}1LOdV0#HTT>Y`&VN)hXqTpl#9nlk4^XsU1e9!utr`jJ^`qygBn#C69_3cQf@WJTOEF`OMBY6F3n(_jUi|5BMr8)tnz;F_kDdm=s>KGpHAx^|GxkK-->TH
    z(;rWZ&O13h)9bX^QY#_%KABG6*=9$7eSQ7;{mS;0XJ1`iy?XWLdE1_Wj&1nw&Hyfh
    zK>eYU*EVllxqO|ooL$QN{1AwwV{<#+a|NNrZ_Z@Xo+>D0yiwC7@7p35cq^HW)uZMM36
    z_};RV*2VhKR*TEG9iEl5a_Q6V<@~>`{2+-29F+|RQUqq0=f~N6x#0Y5a}+@mp)c
    zOicM?>!wuIz6E<0621xnZ<%;`c|ShnueZqC`}Nw5z18J!?(et%_V%`T=CLD>j&^?z
    z*YdN?on=*d)$ZEXKYtJ_R2vgH=bU{dTl4yOwVUbgga~sP*TX6m0>5e=lD?>c2
    zw*EY$A1f8TsfsW2m~&Lx%Lf;YnN8)3?r&N4D`IO>Sj=2jzE;&~VrL|GT(~ts{4!GB
    zWMnc`Gbnv^WyhOMr$2@Fmd2K6J2(ggGB>a31_h`=RpVlH>qq+X)^fY~Ouz5G5wMy2
    zm#N%w{Y=YcNs2BH1A}JY|9LuG>38VtL+d8p3;x`_S#|2QB^MN{mwrfm+G@PWF1qR@
    za#;XQJ1?{qI$o@PXbk2^I4GRe`;p%-*L}C$n$6mM5j
    zjTUyzfERz~uyft~?sOr5L*f?;XYO0&)yD%W`o7FN)U#z?hGw*u)!prx$=l-wbdq1wNzY|{c+bd%RQ}^w>m@Ba%
    zRZrLKsCjuNW5%KdC8|BW=|~x1!7tW-uh#$5npgkt=N{$ykK*-$+~Rs??EfE>|Kk`p
    zr%J{4&yC}DV&(U1zkB$V@-=b_3b^=i?4Av3CpnmM?g?D-;PcME7Ug9JcOF0fy86B(
    zpYz?~QnSww?f=gXbv7+V8S`dwQz-cI;^Mu{eDZd8q+NPS%v^RwWM^l;H?36&;03LQ
    zlu$hn9wvRPSD?0<`{Viba((arKXHg#z3@tE-?3MY%gwGG|FSYTDJr=3+bp5Wm#hEn
    zeO|n6{qO2)>&`#l^Y+TGioC}YC#9z?xha4&4Gr2_)_(vrCiDLT|9^pQas7AOO)i7B
    zir&~?|Gy)z>awqS?+Y7s!5JEijz?Th?gnq63|VsE*ml1s4-Zd1FW)om^4+5=+l_Z8
    z9NVG^8u8n8xVg^J$$!O!x2K(3MfASd-g{omCGRF(bEo3zo{GxfogSsyUAdW(%RoC6
    z)^sL=G6#6X8N@K)YMlT7=luRJR^_|DUW-0|_o;QGr?x`Jj4jTq!72k*fhJXcJoM*(
    z#(3l$GqVWS=`Kt6%+mRf!|nGNz1x$TxpKQ+^zLJAzd(b|6$y7=H@69Dws_=1cDNxI
    zB@PQ>n3_6@PVNHll?s7uFS@LK*IWN@$>)n6TV>g9Us{;Mc(uCLtZPnk)JG!p+QO+k(=?mn={`dtpUOq!ja^o5(A<
    z8l^;kOt$|y8MM#y&+-31>uj
    z&mVhk+_Aa+rfE?Va_irr!9kPByijxHy&
    zq{5I}JO^fQZ<+V9qrT>6K-~9-KXs3{?fEBqI_;UUeBS9ahch#8S|t2#(=1IB=g~+;
    z-38Rs?hqXvT{rt-i}>S@G4C7`K*=z`34G9+!&Q!w)K8z-Q3&Tj@tkKZ2w$#zI}aNF5`>btK1w)
    ztLivP!NtutxvaObRhjo6zPryS>9f>u_SFyTvc;Zw>;HZ8>gU91Nt>W;U{Hz$oj+H^
    zUGsVN{hsi+%BA1UK<5D1*FU$u-wEpf?)`oK?}dB!!)s3XuGv8%1}GL>Se9DPS;K2Kl}GD+=DdV
    z4zhHkD0uk!^fcY)u_f>C?VT96G!L}3o4@7(^HQ_xeGaZ1Kc>&Bo3gPJ%84lwPW?f?AYVgC8n0_=VBBzFX!zqhRI*N>ms;!hqP_FetVb??&YT~(H-
    zc0X4B0P0vzjB9=SdH(;JH+Oa#+x>m%e;jlK=%Kv#ENYg82g^|m(`u1-JG$N%TeBk!HNJ}Lxq7C24xOm3)ODXE^Z9W+hS
    zxRBM#dUw*{X^THL&zAwE)q**e(KRoZ9{s#&>GVw>9)5eXwdUfNh4~9uL77=V!QsLG
    z^!I)X-mE&+lDL0r<%$UcMqxrmjvh(^3JMA=69rn*CO8^){9UX`EUP%>J}cM!c6y)Pmi%quX~y!4rJ&vbB@Px2ffLe=
    zQ{Fo&252!c2`)9de9W_fq0vV8#)eGyJOAIz()oV)^!o6(Tg%;hEER57y`197?z&#?
    z-|Ou430m;*gfTw395A=6G!oq9*uc;jByeMA`s=0Y&qLFq^=*G0n!U01`8&0C+a>ki
    zb8au)^7Yb%<|>oO>#m?&0L`PI9RM9npd2$*JN(!z)9gi?HW`(@&-?XXd%2-p*^R`&
    zz`($c!&jdRi3)URTo#jOo{Pr849aZS^2rU}T&
    zCu~2`q%%u9I>aOu)D3`m}L49cl%!##kK~{ba3b5a4A``
    z4|Hhwf)3Ve`FG^%>(X+?8Y)U(9^2dZWrg#vw1e$a{x3}bey)1$dL}fpQyRB0Jp!FO
    znsfi&7x_0=Ws;}s#V*>j$A*nxF6Q%=WTr}e1%Zj*gO@b3a0tAJXnbp3c2r(2TJpQ?
    zUbRc7+CtoTUy26zOG>2Aw@}$t_A=z|!MWAjqN@HZHQ#*X^5$n@$NKi>>=p^Z%p#f5F3TyxL`QkF|{$8#|O{2OI`%NzLY36T96s?azy)
    z5gYb=>uQ@4W3~66MRjS-OJU)pyT@b;zrP8+$E(jKF2R(VW8$WXNK(Z`b*c2f;xpU)o-^Je!Uv*
    zzCG{ms`Zu%6W%j13I4Qm{^j1l(8wp`p{@AuaeHy{!>;Y&jwV-nMHc)x5k9YP?d@{2
    znWq((R$4r}PY&{~WayV8U{#%tzC(RBQR%vZ%F=%im59^7LGj
    zJ#Dg|l_uysYH(k$Q+-~?mq^6`4JIbRR-@owpzKj5=5gE5RJ7$pY5MJX4X(*Am$>u1
    zl1!Je*6_10OW=8t{d(z~nV_vSu#CYWppo0SYSk)GucfWvf+PFYLocqckN;Nr_t)30
    z=a%zNR`Wf@B)ERhr!EH)}#){#@a!K<3R?
    z`GwuSWq#8QfsUxbe6>{R!t(R?|NZ~8tMv7v^7r?yI{Q~D1x0R5a{apVj^nL)np3aG
    z*V~q#vTke=5a`h8$h_pq#KN&7hD&+1rDS2^0=f;F4E>Tg@tB2)nDhigoE`EOQ?7HPuJ3sw++@IdQGgNrz
    z=X;z_b~`MudB5NvsNQt=&An#b9VtzBmtyb!yt$80|F7|37Wefh}v^otUVcz4c?G!#?f^
    z!HMsUm(;Ux2xPc7E?sSYT(>?>>bu=mwX%0!)uGpJ6tC>8>yf*)x^uN2$U)$`02)Q5
    ztbX=?zwCHEuX@uQ{`GsmMfFITuG)2KX8OFDtn#3-sUP>g?+dTBlU?F)bW7&ttht}j
    zEM#wNJ#Bt$dfpuI{~!L_$<|jTeZB42vAsCW^!3Z&e#skas!FWKkUE8lL)eAu;}nUlBC*J6i_-4=C*
    z!b8@-uJ4+|#QWTT<%zhhdOy%C;dnFIAv81;G)fzJ+p(GL?PXgNr2r35nP3wA%d3H*
    zQHm-1dTy_zeU+xz8&8wi&3pEwZ*{J^`}M~wi^n?{KmI-*c65_zbXM5P(wZxZwclA3
    z+Kyjr|F*jH9@=&shXuJTWp8hV);?zDvsm!!24iCqsIt2@(^QX%r7KEdZOe~-`Ez$C
    z?_T&(luvX0;qQ6(C3b)RvwY2(HS>;h3iF@YmN3g=lmFgqKcwgf`zBX?LKDBTTTcgQ
    zXlZf3omBdq!ejH^PPE>7m-+5Y2X^isFW)`j{7}Kf!ttit;nd9wAp(nj&8vRIZ|W?d
    zDfjW+VzwjS|9@Sv3I*FpWAva_n&WLux!4WO&kBKn{SqBK^r^p#FVRS
    zkalLq48vqM@F7Xr*Vcdz;I8@eSib+?-|XjkIWJz;{{GgRcXyX*$w^D5N=*fUiPJAH
    z3I>${Q4h9G?aeCT6rCkus_-USZ14H9q0SVJ3;d}m6g>HT~;guHLj}V4K9cN6%
    z!`6*eUtiU}y7J`Y$+h4$uN?b*d%~kN3?P2ls(Ud6dV%lS=qk4mAn6Mzxy%dT)R8@6z9Zk
    z$zIxuEQ;TRBa1<gGgxa=`0=lYCPQXrKyd?4
    z!zOwO`}>aN#(-MvC=xIg-+~2N%`=OBJZv|wyz9#JQ%yl&V!rVr
    zdo33NEt+Ho1Ea||*2h4B~0-fUj=Eg?l!!s-j
    zl|-0a^%VpHzXazrKuiTY3a<6ZWQX-}dy}4=m>4;Inoi^-|JcjoOu0%50vFZRLyZn9Lo<-U$T@DTki#XIS3P99AQyesdYUnghkxu&Z
    z;^M}Pi;I4o^siHr2#mPAe7mm5gf+Wb6IQ{NVW8+usAt_(`daM&ul4_>jML6^{C>Av
    z|J12dkM0zo&%KuW``cUTm3y5Q1hB9uaiuQ%g0dkD>d(eSf-@|O({y5YnRv&{Wh;HZ
    z_j}sU>amgsqJd&Az^_*RJ;0kp~BxlTS=gEc|p*
    z{rHN&#h;cRu5wz?%ETn7%MuJ*sEBIfTEz{?$NP3X?z4XMegFU3oO^qAUemq4K3*Q&
    z54v0Vd~V?-PxYfm#p7j|+4DQ&+EBD(7#s7IEp8WV&@78m_9To_%tm)8biM)iiOB3S4F0Thq
    zr^lZQb6Vo~_1#_TWxlh;md`2j+9n$u85wDI4K#YDy?&2Srt6W-=k28P_k45%FGo0E
    z^UT;aHPPTGD5v}>&S?QV3z`aGiT}yW1F_|IMR%9K?*ko(2wK`BVOv$QSFY^!HC;aY
    zKOf$dUiLLly=`%Jo~?C|K=Pj-AHTk`c2tOG%{e<|z479BY=(-gJupetd(+0b#pf(}
    z*%V*#)%^PMGB7Z3;@r3`8G(0C+XpW;0DX3Y2K^D)}CrJ
    z&AYQBjdy+Ua=*eGiS4PS@zrm)rfm)EblAti;qv6P&kOLZ0yrtblOH3Ks^W&)-`{eg
    zmzmtC`}@nZ`iy30sn+W7^?7B|qMXR>2DHEsPzW$$(zN{Q$SymjxBTOyqi5yH*S%Zd
    z*gWg5n=8{#1qFeL{F@gbHb5cyeae&rCnhRy{%H5*g7e1g>+AOR)&BkUHFDCckis7y
    z9)d<98f%0EI!-LVc|jaoUFYSLaA}F>O^f-}?{rAPs
    zsf9OFryrdf9ye2UzTaxOcY8jcQ~Pa`a$>@d6Yh4GQe?$BpMcD;JJ)50&5VFAOn-lU
    z?Vf3ze$4j!9pUYF%c7SgxHzk-ZnyjY=X3I{EtwbBMsIIhW#O){o|Q%EQ&m+7(&jaI
    z1UDv$y|}d0drs-K$iiEh%a3kKJ)LxQRp`c|r>8u$)!2BYrtA$WdL?IDC1TvXQFLd6
    zgUdw!4G*z7Xu^M{ySvN#4U>!6@?Ki%U$wkXz!Xq5l+fc@hcx&JX4PeAfK_8oPVfuL`_mi{6&Aa$i3)sAzL_
    zQ9Lur4!!9QN(%uKn9}Fhmi>9@U*F}}%y#wGEO1*TbamL<%QMvc=k4)-Yoc@^kcml9
    zR`vZ(kPbxVhNM`Ly$5#R`?}6!{jR55F8i&nK9$bos-2L%Y|-2(W^6?QNSCa>g22U(
    z#S7T683^hGWU%I(4cQW$oq$Dwm-B*6n~Xq{Frbt_r~cp1!ef%@CKew`{yw+=U-{fUe)k{}AOqCuUDYAt<6Ei(Xw^?0($(-p9Td*Vab6mmD?bd^5el;Yi)b
    zO!Q6*D1;r{IYCn|?{>f6x8vut*~y=uosBdP3Rtx96R2(fBu)K?D&Xn
    zIgx)ri|h4bcOB`GG+wl3&6;bDa2KdN8<^R!3unW=)xZbzO@kC$s^=RY_1livab
    zP}?ABRte^@W(^FDvzT6ATicyq`#KuDbYer|VbIuSv|!+7zvScde;iSN^klOCx^hca
    z)?2IpJTu?l86ID2>Sz1)N|j^B7OqF2LCNb=K^@UEGmRg=j{jd(@+#%}-zo>cCuEHG>YEz-|kzgKK}TvcYx+wA!6W`4UJ8&`cjx4gmm)}s~gR`1<+$A7g9
    z=nUvJ@xjae)?VMgMM!DtmGkw#me+S>uitBC_v>PR+QIfMlaju@x%u^$g`>iJP!UjB
    zhB46%s=6B4ScB}^^Xop(F8p>g-TnEwxzcMUuU9wExgjvyEcaBHQ;&@0rZDr%*8)F3
    zKY#vQ?T2RhGhul=5(WyVt0zVuofzh$!NTR~ps;8{nm5W0BUnN`!BX}8oh-XdfrDe#
    zlWh%N+6J%I9Re-yUwzy>_tuuE$JTE)9Nu((b@=*qpuvKldKcql{B}G^}36y(Sxcn5Jws<`K`F#HR>)%1C
    zO5OhFNzf42-t64Mq(47CMy_jrU-R4=RCe6hnCyP1>h;=<#m~>>oL**p-e&W?eo{Ig$r9S(9l`PX&)eaJzdnSIYTHr!usGfyT~+k$bw
    zKdX7F)tu){b<021G?lDh!1BjV^h(LgoO#?j@%wD_t1CbSI4Eyc>OMVv{ru1WmjB`RxBVKjD4>yc~H~q$jxb~
    z%Zs!%z$0?=Sw9&GOgx|P3uAQ#s4<(!wdBF!4-XHow!XjIf4+oSPJ~S5lZhYS|Nr;?
    zsb$rQG0r?*X*jL#<=L3yJ
    zd+b!a^vy?oPJz?AE#J*VJPyu3E?;kRDJcdjH`aTwM^Ql>e<%oankGe|EmHWQO;-gldi8
    z^QMZ+C8qZ4Ro-j4>nAe_zEyo|iKPhUc(T^v`@6fF_dWgOu_fI7^7J#w$9itQetc|u^8E);XtqutdH4RxCd!Ex}i}v<*tZjsTrkCqa1bfCSX#Z5+P
    zegBN}U*9~vzFG+}+v0G4JG1A`*Rp@-ZTr4zXOj{u+ofr~njRCj{jYktbUJ7S^2gr%
    zn#C7G4KjI-%T?!Wv%MnhZ!__!iRbF_Sz6iG)^w)Nt5jP(DeS_M26wwDe>g;+Hn)HV
    zxWG9Wxit{5g-O%!>t%oYxqn-$&N?o${c?Hw;Y{yk_x4t&N6TN`b8q5t&HD%Dmfw@y
    z|MP7ACjIG`zxgZ;x#ZRH|Hs2SRgN9A*fbp`GKsFtvzzWW*UI%2chSw%>8b0t=my{V
    z^>W$lysS;PkIUEBOpB=nopyeJncpPRJa*6bd)1rgf1L6?<->!6)obs^iLSxfd0TLm
    z3g|BuA?uhyq8nDKQl{H>KVzycPVviCgbPU+|-QGmX>JZa?*zVW3#;fBXKK
    z+2;DI=kJs7i+;M~ZON_0OYHtVV7EWa#O5g+Z&&w^=FW?kv5L
    z*lv1b|CZ1jp6YW&zTYYK|MOJ8zO(q8t)un`gWGTA8V)
    z`{6)$S<&e+MV?Faf8AcaB$N-dUTRL&tCe5(Mbv?ARE1Z%DF>&lumAgc;=e=t1Wvt~
    zuJw3U{Mr7kuWyx^9{;*sx9iKT>qZOmxBr;VFC+ARPQinH_ZGRn)!X%AQN@>w?we!y
    zGH)+E#w7T1ndZh)E|(?qU+*k_ehgHwvduTmzP9GZhD2wXiU*B`m7h`?JJ_bq!PaGM
    za4=>))-S*RdTwsky;bi0a^MRRtC!Y(xh%fz>C>l%2?rX={s-CTvVXl(d_MKA_rZy~
    zRM)n6sIq$6{XFUKCY60F>{Xj|-ifgMB?+fE)#n6kkBqC!>sN5e=CNV*3X0GFcm8qI
    z|njDkDvX{J_@k;G@+=c|lCqn7y_sH
    zE(e!=XFL93)T5y3@GDH2OP#e|uD|yB-_t5DvpHT~b8K^OZFyty-9PX5ysN9jpZh)i
    zTYc-DMsD?#_o~}XgR8$8uRZ3O`u5h=twoI{SK6njFUr2Y?qbBHS6fPhwKBbzeLGcr
    zDZpOZTHW0x+2|a$Lf>HlFH6X;o5yg-(Q?4*H*F$y1yCQ@QsFNWK-@zS^pq
    z`KwOfV)c8&^ZB4nJ=^l{&&xF}dot1encwrPyB%EOeA~}q4SX&p&Hv8N&&}PeKNVEA
    z9V@*aE51{A`Z?S0ciwnEoyDhl@avk$&6|REii()77k^xMU2pCq@A)$>q!=i%DhACB
    z*?z%GPr$I`#f7xe+DAt^uR3;5*{aB4T*;2y8;kdSZ|L?nJ_xV?cPf=d9_oyxEWGt*QsAlQ2c+>&fEAaU1_4xiN`VSs7^Y`tm
    z{cV=9IrsLqis#n%B|)tb9vO=b2d$1)8Lcg|sP}R`__QG-%Pw!{(`j#tZl$eOWo!xd
    zvsBI7`}NwZC0F(LehDg@|7G*UPkm3a1v_B#n;5at6}P~9x}IU$nHhWgK5x0~*Zn1k
    zD_TKSYX8S$(#Z##SZ_LjZhdw?KhJiy?Fx|{7QbFBe!Oz|ysq8vc4=Q*8$Eri?cXn#
    zXV>=ktFEcXw`N~Yd){yR?MB7*-SsaOxdt&&mJ4QuPgnJIarG^zB9=y1`
    z-2ZDO`&;D+VTMb>ou5wTK3y3BI}2d`pOhy>=1!^cd4AeDWp8hZ-rZHYI$S??wpD4?pY#9!_%BH}6T5I?>)E~6
    zcL!R}6X?ir&*?{79s+TfgOEqO(eeX_xb^o0@J>1{x}oy(GterEuRlvBObS`9zvr@;
    zJ*b}Rkv3mpVZ}pcKf}nk`n_8~yoZq>tRDaitMHZjW
    z7;m26IVF9`!lHYX&r=z@OZNBaZ8cx_>czbZ&g%7=wEpGs`|Bd_PKkC>M4pt!C{Y{^axZZ>bgWl;bIWDT&cfo;*VaaFUZuI8
    zkWEeEphURsf4!H--mi<@s#x%3qI(+i
    z-mll9K{-0B=mO~aruVh)s{Yn^|gtyX~qS!0s8#q&AE
    zn;4G#`T6;=^!*=hK65M#L8Te!Qg5>_pi6P4=|(3V?GpWX!I>X4Ot$%R`kX?y9!cY6
    zH!6G9pI~88>dJBAZO0Z3f5czh*;)K&{{PSQk50$`D_Rq`*Xr51xwH2c+3x>-ue!MX
    z>ibOV2Q%_iG#DNtLrzdS&ot%jr+MGjz4yXopAt;AVePF5XdkF
    zP4o9$>%~@!D_q!cAbj7asS!I05@kxS1cJ{_c<6ObNJ9v;#B8R=VJ!VmhXn>Kt5&Ug
    z)G8i#!fN&>2Mw04*aO#mj@lhQhI-Bl#2F58oS^ZwUG|`+%h!#}Oh>g81OnF>XU9O~
    zQKRq4QU@-(9tlIG*S8n<+ew)+3s>GuoU629J`0pT?_G*s;lCh(DInDFG(iQ1x}rLFxv^Gx)%oSVzb
    zqy&-I0AN_@74`r$L40*}`1{L0)QK5%owDY@m6gHXWpCKxs+i__<)3iFHhu{TPL3_p
    z8ysA!J*)Y!hBk+Qh9hIN@ze)Pq>ZpC_^G@h^YSuKza;tOB-Kc!*QKwoxmH$Ig2vyf
    zeP@|yg2pHQyxcHPAY);JgA4b;5UlG19I`obZg11g+w<`l=tA}6*Voqe-uv`yc7EUD
    zJ}a%Drq|AVmP;;H=?R<&XN)#}`ufZZELV&$GP!DlCiZ?jGv6=y{cd^uWXBGf1E7gA
    z(C%oRhz$zhrFViGloll{^K!?QM>ND5LDkE|ChnD>*>cdJiN&`Y$;mG+EWEhffBubq
    zwbk2vFMI3n72&t};2_rE@qFLM-uxq=13_Ng-k!fPK*F7qgTrOY0TpSqwXTr7^;6X#
    z{oI^2&VPS@@2~&8y}nye+3m`!gzM{K7l*HpGt9ZM0W_Vuu!X7&n#dM>l^uFHvzBYfag3DdT=~Jg3ZMXZfP)B3p
    zy0i1`_veYu=X|oY!NDcYzyBPzA&`I^CQSkGSYU*(noq{J51@&`HSaDh^_~rx7)!`r
    zRx^XO7UCUHW~*-^y&YMvqd#6~x_^{gJMHMLRZkx0c+tE_>6Vy?&3;w!FKy9{jZ~e>dmps~sN>aX&u5%%8KNZ*o32hszI7
    zY@Tdzu;$+LzV>~$yL_$5v$M0s_y2jS|9FzOUgj3|(9lrB;%8?-&7&T9dpkdyk4M~I
    zi`{O0KFwCf-2UtRjitwzML9?B%S&8xo%wTqx3^ln+~l^oF|Vt#Ydjb`Vgw#taOOW7
    z=CI`VvY!$AYAQjCf(!50eotjw1ezlNt?as1krQ~&Sz(dJ@~aCVbt`JFJdxfgXIph7
    z-TwE@9j{icegvA|Ub089{(E_S`1;egx95Wk%u8a9ncmCz>wg@+S>{)&y{zS0=IRAs
    z;&fD573+Tem_AF!k1Jq_mAq}8+iVu)B7XbNXNxOKItXBl7<~w0meP
    zPibRiQIaYvoCYpQ(95k{wGVUO*Qf_wdbwqj151yQ^h)T|l5?
    zMdL&Cy*`j=daL;1QMbNZYHI3gyR6U8&aSQ6-?!&x^XL5a+hv1;|9WaG2g!AAR{OVp
    z*{ZF-wkkTeh2&qpa^dXdvZ&(c=Xx!RpQU)Nzsxngk(vEihoJJKDZzf7da+Xfy6o2O
    zm|>b7wuHgmYuenf3rpTE^t1c<#N*^SX|45pK6!1sdOdsn-f4HsudE0(Ogz-$@m@Ao
    zN-ov?`>D@ZQ*po%CeSHCYa%x<3w58dujJhJPnS-qKbn5NM*CWB-0f$vyMI5Ot+e;s
    z(l2i<73?a${O{#-?#mARd`D(kgUj7dzh19DzV&+CY*wvTao+PUPm2kUDRkwLwc2v+
    z>6GS2tK=|pW=aqZ`ExoVy4;=f<7U$>gS?dz_O$D}vch??pzxhj>pdfk@PkYAOz
    zqn*CY%8mXVp|EJH>s=f@PC<*mUoL+ST5O@WJzOBEerwPIm9Jk8^>C^o`&&+Rnwa@?iCLKKTzV+6<
    zg2TL#0*e+cQnLFrvEQXCetTXlXb$`1^!f%k$(}U`rbjWf6Q7Z@~kWOV_-l&GXLu
    zntSi^H}`(~e-+anKYrA$->2Mfv+3RpKdYBZEFQK9Kbqjox3V<%&W^&1o72yOR{02>
    zxBp*Lc3;Hh#8l8&t@WNSm%JZ?mPPjkD}6FdK6d2y{r~@>I8O%u7HRR=>9%gqr&BsN
    zChk6eV`K8>2S@blK6d}O`@T**c)4G1+}^6EdfQ*`c5vBURE=^rEIbo?xhv$Bhj6S`
    zDvCBXH8cKxzrKD+_}xjLY?mlFoq8Ei{(AAn#qQVF#{IPvPw-H`^v!RlgUcyRP*J@m
    zE{Zj9`;}U^sE-r8PMJ>(i@BnEd6{o_bly%??y^09KAkQ+V|e_^+Dm%#S(R?J-gJiB
    ziOdM7V$yu>kwt1XiMwBOQ+Ed9k~|J}9T%i`~|+4*i>e0z(Yp89dI
    zzivuybIH%A)6=zui;^>5?e(8;cXhgX&W(WDIoo2S?CWZ5e!tl~aa)F$w(O--UAq`N
    zVw#tFPfu&loa*YVntSrf{`&tqH$aOm+g5EkZQ0mSmiSEoTeFShiuerc^1M6M@Aq!Z
    zxw+}h>9@Mk+peq+dG2#--t*e`)$wyTAN^W*>c;0sjX$>^y(T+*mg$Cfu~n{Fm%~(9
    znL%Z6)OLT*MVGUh?f-r3pSUg9>oaI6`S!56UlKn)I{NX$VSaZm7SNc%%~vg3nig&R
    zw6VWdXWhPEuRs^d)_mW6zc>Ext8nnxLQveqS&ThfTtoCaCN?R8%#+^pv`^N0(`Vkb
    z8!|RHO3xAL$Y2iHj(x;6m?@Kc9%vBl;|b+{lhCyXvtO?N*u8g3`Fru{KKpFIC9mm~
    z5c92>=O=|p*Zepvf9{hFXzuLY{mrGpXB}L)LY@eDF0Wg9l^4_OjA=Kt^e=Y>3%|KSJENZ&~AUwdy?
    z=H+F+H+RnZnk~273^ZCEQ*zPu=J}KP^}lcHC`@b$2aRC}g)e8hwzKG*plTP}z`qyc_-8y~N?{>I-W)Ru!8vNLsv27zWUw^yU
    zAHBGUj}dFuMokQr4~P?N=eJe7-M4aYxYL!l`FYlB=h;?=#e3aWwEg*H^3CVo`g=>}
    zhbu3c-@iro@{^O3A9rc5I}zq+^Y6#wNCl$IAx||bC$w|
    zTTId0^Lkair=@J)`{Pmf_n+RcuDuK2cTb;H>fEd!`)}z8e*M>D&B_>8^YQ2#vE<`@
    zYxjkodOu-O)bdLgrg?%^ca`3KCbLA;IQdx5$w?8*uZrv}da4hbkDC>t8ebSxY#{B-n((l7TXZ6oSNUa@1Oe>RQqu~JGZ!A&z7yh?$iG8^p`B@
    zNXIt#0$R*{>EHjuZM@y7r>CV_vZ(pZxzXld{Q8=}j(59WEA5ri(tI#sl81cRjl`?d
    zgOgrO*b|Q)ZRbMjmMME2eg#?7Zk)TX!0vI6@h1Ic-g2tv
    z8NlQA@-+o}{{4FWwQ5?EC#b3KIa%%KmdwkW^#8pM^I9!>Da^C{US;~U+ls2{{*|(z
    zGU^9tM>}ZGl~~7#wR1e)Uj7RjS9EEB96XRAcIdJUC%HYjUuD+Br^}aPJ^H2-t
    z$IbKq>b!p4#LBI-H^}qtv3~jaUpJ=B{${6ldozzpG_y(GogLrm%Jx2AnyS9?iF5p`
    z(sP_ltQrr>S23vjPX8Qs;C=8tzurF41r7I?GtDuHJ(tb6Ke*D?)+#)Ksct@3&Y=?X
    z^{kiTOO_YCTDd&!{lClzg<8S6`{wx7@3l)l*2A{{Ox}*An_E>T6uB;0JM~gESI&|L
    z4qBPr>vC^zbLFbIqMOMLTEmdS*fT|5>2J>!UWY5WlkJvQFH6t8u|W~kQ4ke1WtQdL
    znt8f-=l{H|N{e)--o?HetCyqZRq*_-v$M^Qg9bxE%PD8i-STV4|QUms|O>
    z1Su%wP7m3>4w>U6(o&82U5Us|oIdUyTO+^C}ewQIEnHm)xM-Q)*}J><4(f<4Q#
    zGc$wtzV-Jqo3rghrk`j1*EnN&$KqQnoEIpwvf!H+5s$Ai1a$#jZZ$1my41a2PB(Xv
    zT_c~UK*x)KI(}?@-3217;IVfFm#Di1zg{j+kAC&#v?U((meFc>C(><3*1v@A#GBv%6<-%A7My6^(4SoIouCA^%*M5C{{XOV*DpMG8@!NXBx#(|6O@^iob`1kw0{)Tz4^%|#fbGU4|^Yz+5wr_s^*S$>PmT@>O7dxr^4Q8{4b4W-vcyYEy_0Wm%e}ed{l4GtJk~#(
    z^7)*#{xbjh_vWm6C2)cpv}kn(+gvmUfPKDT3X7O-l*rVnQ-7O0(T(2rCfK@{qhv~h
    zgNysgYVeT;@KAv=RJ98pwu&Enb#?Xk%s-RW{qGSmfMSGXnVjCL;bq=R2XjnVbtKbqZ>{L8hy$SML;~zoLd@;CnRr2x@s9awY
    zyW0%3bqrMND>}CwIjKHh1~hs+pYJtiqZk*5%N7BjQmm1>rR_kUtTnj(asU6n?;9&W
    zKa1K9>hFP$P_-_9KDYcBXf_^n3M6QbD$G`%L!_x;?M$x3Xc-mW?G}GN
    z9Nv80*Zl63+{Y%>-`;pQ_I!MN{QBzmER8jy8%%@uo$IN?Iu5gi3DmnfR(8(vxrs!}
    z3hNIqFE4j@b#*PPy12--RR6aRfpxRO9?^Phqqb^EU)xdmc$VoNzqwXN6We8{U9Ek)
    z_4=%KiYV2PbN9QbJ^xDJ=)Sy}i9Tcjl#p-(O!}e`B~@<=V(%g6tqBW%s@_$9{um0M^Cs{$};<
    z>+9?3o~we7K0Mt1e(OFimQS9beYt7Q;9CdLTr8l$+2}c0E%kBDyPeM;fsQSnV!mkO
    zro_W-KYm@`F9(|Kp6bkRyJh35bHXRQ8}%x0YR|>qY!c+2Q}^rT$0w8hkIk_xe)Mkl
    z`#w
    z9Kx9naokg;PCc4BJyr~~2y0r6)!M2ZpU+v(e)D;PqVprr0lt$yt`7X9?3KkJ3EoNe6HB(
    zX}aB^tHX|-nyRh5c7}vWM!+|(lPjygya+tQb1du$6O*8;-N81jBmV!mOWxnJJ=P;R
    zdGDwF+p9blq%zHo3X9FfT0(%zLx<0-YdSLaO`U};-3i=KZ)BIRF^H>tIyL90^R2d(
    zs!#v@e&4@*ew`I)D0#<=MctcnXGdL%i)E74RS>v%(fGknYzB#Jb>LE}d0&11^s$Nu
    zjqKYh)~q}`+23yF-k_$}m;LSc9{qly!NHyD#;ldfUv059I~o^>|G2uoZfbAgi3y6J
    zGc4C1eLUABGf1ZT&Bn;xpi$zD$;bP|?mIIx$!aR#Ts!0t$PL=CBBmcVr}yKW;&YvP
    zvEOnh&$?nZ^%P`je%Tv&rdA~dfj|x8rSq}+WX^#*JBwHU{&TK;-{xOCma;!S*4qtQ
    z{B`!(nVFX_J$ohmB7m{6gYW700&HR475Sjo{N9PS>&yM;Yv}9WU%!w~&c-5pf7#nx
    ze|PmCW4RR#sy?uuGnB54Z9DuGKeJxG;~2N$~B;
    zw-{Grf-4>9CW&RCJg={>zyEyW`+IwLTU~d_OFd$D-^ZEht&W1g#d8njuqLUO96fTj
    zyQ(&T=9Rw|dh<`ykC&Tmo_}tZY|V#*y1DBJG_Yo{YH4XHZP&fbYkp^g|7xYOx3@&?
    zf8RX6YG%=DomKu83KO0)F$q@MIqt%0`$MjhS64L8Sw5eW!vI>Rm%VPM+NxEnX4x(f
    zY1#2|*=+D!*sUeGGg*{oon4+Z4>b3B(&Ysk$lIXwjXV~5RI}h9tN4*4ox+AkaJ0>pk~8|o#$)yuC0w0kKUHkY5i`8a`o5O*Y(->WM=HWB<2U|L@qgU
    zE%WPCeq5gaPbBlGvsV7z
    zuVLS^v?hLSU}Sy-8bq7yXSH$xZ^^zARu(0%@^`&+ki8F0&W&XvpvEL1Ivz@QbQ4SDbViIIE^tHmaQp8~+$C9-(
    z^mf15lw)ywTWlyd7!JKHtBK)HZRr)g4U=?=j~7gO$t1p
    zUtc#Zc;Uu-AcQN99vUn9D?
    z7Ydm)SAZ7E9X)G)Uj~!|tR^)H^-hi5U3L^S!1LpD{J%+|l9oj&B`+_j&Z~a66Lexm
    z^3zjOKYp+O|Gn3=d>%t%t%yL!4R?#Ph`Jr&!xt8frLV6Y-M;VZ+KQh~rzhXokQf*j
    zH*al6#wvGE4^^zigLC2j53Tw~K>MUZK}R;#{5&1s2U^vm<~K)TvbulXE3qm*e{{)PzjuA@+w8&*2if0m4F(NzhCSbOT5mO<(-L9O
    zy7xJ?-)`RA>MmEQQvIEuk!h{Eg22V9Y45OBh1Q%)=J0_Am^U*xJwG@1`>!jl+~UVR
    zJw3hHf4-ez-Jc&-U;C}!?Raws)M>OXd$XeaE+-Sqw^#>-r2B8TU>l=b&dw2nEA@Jif|H`dg0C!}idtb_?hC$<$C00{?XPcSc
    z`aDHmX)0(DTGVk?CYC5Y1pz#|K7IPM<~V3Y#fImZqDSt1@-Vq^!IO#Qo0fvW#&9K3
    ztag<&*8TmJ>I^z|pxHTcZ&fL1Yj6->=P{uub7FKW_uCkON>=Ugbv>c0!>&r73--62
    zI@kJPi}0dg_4wJ>n2VYY)N%aiy~S_ii*3$EgQsze>E$J!lQ*3MOXE=V?aw}w&mOu0^N*pcD8wX>G6K~_}Kf5
    zj7)2l6$CC?^}U1NjRWiEfL0e+bA^P39h>ZL7x}(3^Yzj%Ua6Ot`EF$r1a-Cl|2hA^
    z2Q+uLvEbpMh)pS;p!Vp8hld~AzOVG3Q~7M>*LTlZ7@2hW75$s(5}}nudc2>`u$=9L*p}U4i}UAUcOixB`yl8
    z>-@A8MVMG_#W`$xwaxq+3pRD26}X$2m;_a=zp`Om#tseNTX7Bwi{AFy;#w6mWle*F
    z%SpezjaY{u8yFh5fet39PWFeIhmiqrIk+y)P26$*f7#Y=!jUA&wFd77-sbDlC(7r5im_A8%C)U#Nf==VAwfRS#
    zx$DIB*US*jUOg>6mko9C%&b!RsT=|tzKo3>m*$i&#xg2-L8lRA!OPd_>!T%Jem(H#
    z_M=HBrypOEsD6FdJJ3qiBBpI=r#vgL4w6rE;Bxx&<)i*pZl^12rZ9;>55ifX$k^D?
    z7BUCR-qe6cOqtfpwg@fSse08nSA>a${@k7&!x=bTV{MN|
    zr3yjik4{DEhIyP^13JA1pSc^iWw~~XUJKLB2c63zpi#%z*zst7vNE>TCb(^^rXX-J
    z@rxXm<#`JAtiQg?U3qklS7Ut!LDMcMfkQp}TVnRI!|n4fEPB4er@GHNS%W$og{vcSjT
    zF;i&t{jS;bf4$!yR$k|QkF{<$YGi+Y
    zUoN^lXVub;>M|SCQ(a7U87(SazV74q!_!;2X!FF|yiUS_)Ev!L#9aCS&)mz^SIIlQe
    zV^Q6?4s-K$>%wnyf|8HO1m#7`+TgdcA%&r;#su$xyLV~?R6SBouyDL-2kjAmkm&`A
    zQPf7lf(xu!YAf_k>(*o(T);LZe9MAut5`UuENXCY(LA@y5KEKfhVq0af&cf{tj<_Y4dslD9ebr$VmT;j!2{NR+hl|F4or{^N{%*o
    zdT#&T*x+?#RrZ?>d3DT^>*Ey2h;mR^lqnyMrNu9@#o_9;?T_|VZa>ESIsf#rKx=gu
    zD^X#-%B!l6HnUtUjjd60
    zSg@6aMJdYrQY~up5ZnfQGV#FuZArH#Utef--`Of}$K;(XS9@dM-&-0UWAw9Vr=rxe
    z;%N+xYAh^Dvknw?g0&#J@t|h^KCUIY)8(Q*?5;>Wx+WretIg|Y4WGI!YF=;_p6Mu0
    z*H$d5UB6d0Sb1WH?bQEb8&=F+Q1!;q{m5~@8G=vm{(hSG5_D9~Suuf*46~_SsA(9S
    zs=viASjlh*l$2hd{ZHz?m;UHJ61m|NA-IRe(@?^l$*&6l5bigO}&&>vmL(kM{(_MmF*Wg)-w9Xn%g?|s_x;?BzKKYt7VUrVqr`VJ~q8lQ1+xR|(m%3}0D
    z8k+<%-d^R_)VL6GGx~wT^=&&DTVno-N7I+bi8uf5$@#TyosfdV0!bz&!LtrQh&!Lbeiu-1Q25UpRs7W{o0YF9OP5z+
    zNy6c^{`J~?vLz*A6*o532It%?e)m$f{^Z?FC%(uP|37*r_n-7|D4|3{w%xncqaD!b>Du?uz0fL#-`fh
    zoZCAstNj^U*IJt$pCj6TZBOmyzWMhrr=9CMo^|!^-t_ZJH~k81iz>bMZvwZ$m3>>b
    zznu}3^lI8n4C7yfEkZwqvha=k6|Z+jahzZvL^hwNpPHdHvnw
    z`NgfTY<9mnSdn+rdF#2Sb|&@>6S6lxul+tR{P4#Xsi{)dIThN=LUu2FJLA+TtD`I1
    z;{<|_$HwGauQ)dEfej-Q%Pdezh|&BC@+921AV$4t#{2!>^i_Ubi<^02&c^qrU$wrs
    z`?K@K<-PysEjTYP=M=cX&)C@U_rT>TXrX(;zi}In$d>Q%zn?EJIJ`HjcPc0E-OAtR
    zayMq)Zo9E(ua?>0|8MVd&QWoltMPBf??+M+2N*?4OC~t;P4s3I6n9~@31hw9?Rx!c
    z?d$09>sQ-%ywN&kr(ZI^?pvizsi5ngiT@Wdb=~>Cw87vGkMW)9JZE@{|Gu7nH*#)l
    zY-nukP502R=08NHPL-S}`Sa|lm+yY0x`f1O&+q(x>iL^m*IiG}{a+Wp=H;$b|2u)1
    zefu|O&bxT$MioQigB8W;d2_zqcqf|qt!HOuS?Y-;H;tbyRppPHowq`AUFL!#7nVwN
    zW!}0XnR)k@sk3?5HHog3dfii5IC?fUI2_SvzJ<8w8&Vq@Y-CE7)R@t+{I7agaf*BX
    z^7KP1!|U{H%RkG$W|L6*@F7H%;o=HG+x2%NzQkpy7Z@xT(x~`oroYPyP>D|V=jW4g=kD2eAV4LCG%rBVn<9PVIn3+$0
    z{n2Uo_@V3fra9bZx76NlD!4Cl{6@yLG+wW0-v)-pi-H0j60+{q=tJgK4hcHUtjS-u
    z{EyhUcC8KL{<7GoqVNB%FEyQ?z5RP_-LhHs_vIQJs(zo|{`~j;_ni~J8|?UbaP?(f
    z{y5_>9_3r__spEV%s1`)`aNd;_3O?E8(#Ws`GGZGLdfET_J+%wznwd0thPQ+)s;c9
    ziDj#16Pw}8FXj678_R<4o}XC$x_A5eSE15ZRzx50Vq)RwX>4#fBC+5WYOCzaz5@|_
    ze=q;8N-l0omet63p80=so|Wp`-**nL>iuz*?XQ(%)7GgE+dr}WOvU$OFilHDfkkZ~nAaeMA}|Ko3pYpmYB(l=c*UvYX-<$D&6
    zlBNa+7xfs{Qj{ii<2oUU(+lf&aV4qLvo|K8kdYvSj=
    zi>ojF_H$PyDizvHLA-ELR%w&T3TGrb*O&TV#!@oPNDWO&?>r`n|am|Lb_>b;hV
    z`PQ2^&Donj=Uv^GXM*2X-AMoKeEA&rcgdOshn8RDk$JLP_AG{Bthx7BEy{~>`uO=rKaex1v
    zf@(XJ3l1}PJ=M15nPyw~yJL0r)l2u6uAV;6e8-)?&GygctG&wn|L4cu5BL1exAdmv
    z&Wii@=dkv{)?RJLHm?RnZnGo54?LfFIo;g$@5Og}C&=fRFtZ=6?F(a2Y*ID6Gf8oJ
    zQ7kC@Ry8=dERU1?iZa{W*e5LUdSSiW>z3}rzeL)9ce4GF*p%*D8nGZrV8Nz+QVJ{9
    ztmk7k*$`7-tr~Da-bG@|{ZqS2rLXl})7-j6zOm_`&*f!4{+E}Z^|-9Pm-Ey0Ewj#V
    zz5Uzn{F-Oyx4ZYZ3y<_8szCZKV}cgflyHoWm;BJkqKPN7A|
    z9awn6)~;mX<6>;(&`DYERiMbPvu4ec=*Sb|scqhE|0Mk~UVN)Cs(1VP^4~x8f7<@v
    z&aW`}!EbXkKJwhWZ}Ji571dwlUfjR7fBnJRzqiE}e!r>A_eAT=do}Hg`}FjvM9F<*(w@@
    z6|1_eZ{grbVQl*6;3((PA;2Wl&BiZ2
    z8rmyBHF_0j3Dfp<%Qqtz+Xr@VY%vZ$^nLv=r>c8m)~U{Nrd%3pqJDqbab^GA<}Jow
    z{CVDQKD+Gv>3RRoOaIEA|F7TePm;odZOa|LXk>`Ubky>G;d^oWyvrHh3+rBHOq1?+
    zIOt;k)_zu8@?L#g;bT!Z{(;hwEfbUA-Qu-ZP-^&OErGp)*VaVO{p!}SQ%Ffez*aac
    z_4Lo`)Y{a$Q@_tKezfb)%SP?XXZd4H9~C{0R8TuN*E)HzN&2%rCh5nHO})Oyq&)3u
    z@tW0p-c>zWR`R(yynlrkyMA49>5KV-qEmM2Hh$y~skpU&t@mO9P~z}OVr=a2tob+>
    zdHQUx@`p3GLL(n2a7(#-SRmx0!6u-zV8gEZSh1KDI_?`1pWgb%;9Ng5%+;!NT}x*0
    zvhXI3TF2&n3{Hj%E{I2*Xy&@g;B0!qV7<|ji&vJh7^+3#wUIly*IjTB!+g3^b+MYHZkMw6iGweDl6}Y=Sx`m|2~hxJsFL{MXhQ
    zt&Q7mv{c&cOV7DCUh7+QA})A2ES#kN`rw4GNjEgkuHk7mnU-nO_D}NkFaKq=+#){9
    zR=1wlG>7S6B8uaAqMQ+6==F&F3SJBtSV>+JhdG2U>LE!Z@o0&-#OY(f)o|$Tpe{I>z
    z)brK3{|(#?p9C&!cdB6
    zGF{i-tueRk>-07r%gui}t%LTQ+y7SlWo~tyg{yLo`SP#Q*FxJ=q9SE?X)v+e6mUHn
    zzGmKO*jWJg*p5D(wXl2BfTz;p@v~zt>9$
    z9{hLSeoy){FNywz^=>WNupz1i&7c7K@n{9&ijc;SLLCZ6Ky8Va40a@}nWd{|%}d{&H^;8@*n$O)KAU8O^^aGx
    zh^#v8%*0cB`}4yI%eLIOnz;V?o~%pfrzX6ZpSL&q3UmRCL_T9<$49Yp8$?e?R!!ir
    zp{svKSn!kBEeX>Fc`u6yYw~mPefjS6VzzYRhm@0N+bpxT_T8PLuNHo;N-l-5sd0hB
    zHDSdn6`%Fn*XbWHSiPzC=iTq&&s=9rj@xp$``FhlXQvvhyTb=N=jBBfV`Imau)14z`A{|VT#4FwCdh@g3IGSPu)_n+Lr6H@)zF?GPi%V>8)ZB*E+pg+gWDq
    znlr5%6ic7maGaG{<~K9!WvapQJpC39oiityIZE5jUU3_onQ5u->fdJc^5RSXX_|4X
    z*6bAW`ltyTahqYn#3VTRS&(%g%+rmXA|0Ha*Vo5K&kRq=kF2M
    zx92MOr^Y^cTkpE_>)*;xrGd+K#oUZD_n)Hw;MlmMxh%mEq8wr2OVbpBBvH{Jg2=;%9{_HJ6z=9g9yLIb}G#Y09R=U5na%
    z?yEeX9;RlwUq9LK3
    z{=()u!xaIXdSA>xg-id{{{8-m9HZfPr`4aCLiVdjYk3E+ntv=e@!6J}&TWRLo;zuL
    zb6Rn({er>)gFMlBD(pt#hg5c6@S6b;NUX50Nku{$mcp@@v_#xBrdFS(dPG@
    z4=WZGKRhG8Ogz6ZA%EVM&9k;JHA{WTmU^`L*!Np(e`nd~+SkVCUU;9qrv6XoaV`IE
    z>%E`b+gMl6vi~;uE1$$A?}UQpx_iwFCQE-&e>;6;tMGio(zLEP)|*F8epU09+qCWy
    z^TK+M#e00F%(qI-;&z{m)PZjF6B6inv1Ii^Jy3EnSP0Iwv)7m&GuL1C)c?-JY0IrI
    zeeM5a7yJ9ky_X9`PqVRVmPPK!w@SD;QF+#utvl*Z-_;l3{na~fmcH2w^HZ0v3)olu
    zn6oD)ZdqOOUx%4nk0#bhnY`dX6)Y)~aY*`$dS1lucmFT-ev-#M&d%k_GpBm?Ee}=G=sWiF&E99l@$6=6=ogwDW5)
    z+oz-3*2uM%ir@eEe`)tSi(;1$!G_wie($9MC1-+4Z)onEF$a`iKJT*52IUtGjw1y=
    z%VYm8Jv8fB_r(bjl3sg_ru}+w@Zw@|R~Dnbo6mprak!aeUFdK7bL{c6>t;vzb1&rI
    zi-5@U%H
    z6zIrs^^^lS^+jeQcb@g)r^mK8ypTSWvLM_=@cHlXTD!He-+g9T)|M@txcA0_``@qB
    z-97fp@$q}}j0^A22k&>ZXJV|?=lykbb<)m>4wu>f{&V}D%*|HQ7#*N?j#zPLJj$GpU!l`i)*
    zl#yGl3q%-N9)
    z{PicBwPr8)Whd8XH2=F`!_52Za(D9Y@K=_ByuV5X*Qx|KDKrUoi@lko2d(aX`Pc8z
    zzkR!@cbn&Kojc~zeV+auLI=7Ki>zlX0j0Gshpa)XNlP{#n04xc`|4{pQ^UgIR%;a-
    zA1T^1uj{~}TcMdxZ!Q1T#5472=+vh=@za)1+CJ(3%B%J3d_wkY^V+b`=;h%l`#w%v
    z_1a6>;OkPX*81vVHRL3-XNn*Rbr0QefgWzc=LRN>I8t=ig+Ez8-N*rq;k{Ac-otH94>%WL@_uiZsgt(7=(A#moZ
    z(yn7)=8C@y&Pb8Zm~+0F`67e-Pd3vd*G*oSpPp>{^S*q5#3p&(Ustme(bqW4s9
    -ubYrSrQAEsx~T#%3GaB#Z+ zd>@0e>5c$SlQU~s1eb+AbC7r|a&Xm;c~`h|o*sYonlsRzVdC@71K~bjFm5?w;rPPI z;ZkzI{NM&7*#g0kg|As2?dxQF3~kX(lkT{_Hvam3=7kn1f${5G)|fke3FuhhBxZA> znRDtr_NxhpE<0CcZi%|?cUIh4^6V@-Yi=cxYDpLW7MlPA0UM1kAt$Od&-iZs_1Sl> z(biypL+-Gn-=7@1T|YB#$NNjC0^+}?mi8{(mzIA+zX#?|0w3 z!kZ^S+Zyo2Mgc(%3X4<{Za$iv7%_8`+bQ7{>IDaL(|cAdw6Aje^Wl~La`C*a(eVt5 z+$t^!3+)#K{Jmp7=i;o=)vsl@WncH5Yosf^F2he%V*+pD6n6eiavZG-4lejw>ny`N zW#;Xz&+R95x#zcCfAeMCn^2wYDJLg+EqHlyi_KjN6%WB;ry~VERZb#DbucF8et`x` zKFq%G^6)7igIv{-!3$PqhEG zdEKY3r#Z2&s{6m*+-2dnt^Z&0*Xb+e_88bEjPmZ7IyB|NjCU%eb_y0Fe zvAeA)IsA9}GU@mGbB;V!+jXF4rSb1(_P>nHIx{ZVvpex5UXhPk@h#}YGrx{FuG-3H z=Wb-20HqqgyH$TIFPr6-b>~`ZdXY%uZ238&AzHjoP^UI%?U;fx;uUU6J zBX+ys-U}DznjdgauJ~V+>-=j$+n-r(AAj|}KKp(DzQE-A`sP2oyll-vrai9x`)lh| z&g#XYkxB-3OosAKJ~Qr^|96c4u)wOZh=qIA!IphCo3))~o*r!7S1FX_*Rpfv|Ts5-Gl3tKg9Ehm}R?*nJ!8B} zzx+P`_f3|oHxfBZrXBFGc6NFD{M;Rjyt@YtJ+x9Ha0jMVTt|I9)8FCld}JT4MxiAmk0@~3i#hU-g4yVcdztGr#`p_ zUp^yg{CoS?{P|I5%s0q5Gr0bHRJW;g>OIDfa<7wrZ~3#g{_X+8+3)LLEqMIwxTJ<~ zv7*cQ>90O&|6G0i)VW-R_pICJPt@D>ce?VUzLPDu)inG37=5#>blz8gd0$pOuG;Fj*Jx(o{e8c_-`&4| zU)vY4YfpQhP5mp`u*zykG~B5y-W1m471gn<{z6Z zrxUqJB{+Uh#Yc@7<=6D${w~_@6@ITaFKX|%m(#S&R$uy!-e3gPd!UByW9~o-_nmA09H?u5w?D#8>Z-EK1bg3j&FS)+m(?Bpo1U8W%KXWkU#Fk* z{!nI;K7Zz7^wM5U9W7ZgE#oSY;C*Sig{d!}#_e4mxADV^l5dytw?7fCoPPgrf@=OA z6{fe`Utayavae$j%PsK&`>pxQRT`_9-mR?Cx+a+6f8g(xd9#C9)Vvaoc8R{UzW>wD z%<${7*?F_J-K%=N<``b&|JJPBVwlco4?mH7e~&%`tDRZ6EEwh8Ms#TWBWu zRb|f)Kh%AeYFiI9v2wG`{Vx`sGx1U5nX_iMb^iW1Zts^qr?Ac8h=QU#hfmLeE1i~W z7PlP$HPJzxCXvZ6%)B=0esYP!nu#8=e!IVaz3$tW%jf&?+kUz5f%S=kLxKG zdk@Ry7~5RA%M90?`4CbB9nOQs54af0@Jx7iX6Drzv;M{Rb_B;Ly*S?OHD3IS0EF8D0vd<&9CHXf4A#diGr_4;yh zzpdGm4TgzdHJ8tswATK^0p|9c?M)1gAH^>yC;d4qi*?uMB&Pj;p6Xwor0RW%&-%@T zZFkFVn`B>G^W^|D{}Rys0c&G-o9RYv(b)TSZN6@$$WcxK30}s=j*9_X_)#kcNR#4N z=z|XBJ`d0ipiA@reOX>|+1EU@-?skWpOPOB+m}1@S*rNXU-xq}S90S47Oow_>H_x{ zBK3Dc-hl+0f5P{><^CU|wq}J^{dm~EIZhxtcWdY@>+-y6>yR#nMnh21W*lXWWlfwz z!W!1J^Yi9zyPdatqg~HmVTAyv11VQkKZsymEe>iD%>pf-{=N}&ULP9X8j1=6flU7J zQ7f<;;f_^sSOB^WrC2^1n^!=}8ikmc1VoC|sBdKJ&=x<&w#lK&PraJ3D(i=!lbP`tkG5S-;;?@^ zWsm!;^>Vl0EsL$p)AC&~orOiI>SdM{wmVTLyF8egK5r$PBIsh~k|TodOI8LiUuK$p zZApI3W9gTVy7m3yf8V;k$!2oPkxZc%5sbwyC2y7n8e;42OL2nkCyVs&m|J#BbML>e z>(4g{Oe{avBl!}v$$6G#aoVom?{)|C+*J`&Fxbe%Bq;p){R{N*3s7fziz4XIuC%4! z?p426T$+A<-rTagrPp)*iiXD+rtB7F;pkZp8a1!7Ml99=X@dsWVugb9w%=2#J1Z4m zEv?DxXqT&6aWCyPhk%58W8Z9LCAG<&(_I=4yx`oi-0l3Oc^o_D*RXT+%xn0a`9X z1uEFW#LfA^f@VIc-n&=s9tUlH2i?e$JKH$j@2<_}w6mwK+5dbp8E#Zef5*l@>{)*z zWU-DtZ4?5Xi&}bJ+AL>`111dc55aUH!TGL!yv<-*pmBxYmU_RwmU?qj>djwk zx8K|Ku1uR#K*Aoh+-Y+e_Av8&psHW#xo!FDb-VLU$R$TCd%b?Yo$pK|)wkR4*Ew&C zc5FECgNwtZXZ`lY$n*Ko;TZ)3E++lzo2NJJjj8+j6m-v;)RyCy{q1enMr>4iyXCT9 zX1DG(i7jW@nOKg+C;a*$e@PIV`xOHG9#o#Mj{DWU|3`PpyPeOMov;7*IrDmKxi4t& zDQZ)SCpZ^3v2tIkzW@7P5qsb)hQ>h9DtJ*hYqXgMaD*i6VFeu>xaFkU>?PcKI}~Co zpH98`@cG%<)4$zF?iacJrA^|!_M-}xSKK~3pH7Q5JF@I(xA^t*iMmLM8*C8RqgF8w zI@RZSfNpDy+EI{bX717+9{!cXhpX|$LJ`mY4$s1!b5$^PHr^AvQF7Tgc#jGbigeXn3UR|TZ?OHYG?%lQ~Db!_JyfQHJf{2de)eO}iog)JUH)5-G$1v*~L^nU4r zl%zmoU?9^$`PJb$XomEjX`nK;+`}QDaKV^~Nzk@fb1nx=3&>t1(_YvxHg=rbt(JxD zq!N(YDmMp(Md^A=g|Wp6C@ANGjykEl?$V27DvBG=b8xtPIkU7x2@(1zN*8=)VNtSr zKWl{`E;mXtHg?S0ImNF9I?SzUQfK=Iz|=YpYjil%KPF zzQq2|L;jc7qVvyw0^NV{cH?ommlK@%B)1xsmZzvT@`+Wv*?9aC=%Uw>uUEsDv&&T| zoSk8)oV)p~*~_WxYf`_>GD6>U9RfIfn$e)a_qle z3BLU6>uc_8cCp9b_nGhid6rrG*YsOE+1uY7;bMwaDR|f_z6^8-VB~>6-SK~tzWt6~ z{A&B>-_h2oQnL4}nC_}Pc)uiXSJbOpZ<*@qUw_kH@sH)0U&0k8!TZ0iZNF6ceD3sR z{`2R7MvB*5{IYKMJ1@`?@4LR;%DxOb)nD;o$B*PM|Nrj)KYeO<@SVEfZ#RDeog2IB z-LBV{{(iqd|K87Y<$PAZ%TDp!YUF3x<)HA-Dqo#riYqR?`pTB@^qIKNI z@kKXslgi%zf8Wa&sX?bu&rbNdQHe?X>$an{RhK-~m#WXNF#?@jr5m@$LN|V&&2Ih2 z_iW$oc)Y24*E_$pDi>6lex6^k;@vUn{5fVfQzn0T(9EBDwMIv#kL=Gthdh_u%3Qv5s&;tVZ6%G18b{Bs{qggv#?kkETTlKC(SB5{&u#PN zg7eM$t{)4+<~@?@VE25rw5+Z^d%4fv{O1IuFjn|bW9}cpoJ2u}6?)v?bJN}2$+gCaQf_t^PG{4Pc zSA4YcgL0pR((h(-Cb9cJj+tLNDjq)vbU#*VW!F<3;TL9&OTDKrW9G9^c>Q$p_Y1p! zKAXL{TD9s!?fdHc-v3|M|6T96{OY;$v&&BLSgqh^+2sH(Zb1h(2iQtN$lb{-jPTE8<;hqw#qg z+dg+i;^ss z-Kti5CHpG%vsSaZPvz57WDuCkv*|eVoDl<8SU3*SGx+@4=oB^zGRz zn|WNeTxN>uyiI)~k1t;5PCBw=&qljlg2x3ICf?GVEc(Ts$yQ0gKj-;(=e?fG-K%E( zJaVm2{+jpC8Fvl$%yL;E&MH^`=i{3#i_GH-GiH?4-P;npOx$;F@O$nfHBLw6HY67w zd$)XJz}EAAq7gd^9(Js{cJ6)t+bNQPOHRx9vI4vMct% zDed)V{1#e>2d>Egr=(qX{r__Igea(S_s&lh{Bb*L_1YkticPokcJoTkI{DWmDDtQJ zWCuuMF`8+0{iNc9_e)L|&Yk=82p0I5p1rVtdK%_Z#DkxT$|a zl3py^5f3_ouqO1IoOAk~UsuS;$5L`5U~K9V2ppPuoHYy z$5^jk`rovKZLa=<@7vGqcgylfSj6gPDj=AAJ%9h-Z#U=gfy&cs+K-yJ^*p}ctIn_b z|NFju#+}PH0fE+*8G@YrX4N6#((_<>nH<%t_ootTQLoGtT+9gX72F+?W}% zEe_$_Jy{A$|4#IT&wIpwI^#vB-VgP86-mGDJhuyfD=Bzb&o#^JVcr>jK}{)t<*mVL z+Ar!^cEu>XTPTsIS!L`Jpub-|%U^r`39ESd&mKqq@XyZO7TI-A`F=tCNAH> zzqoLP+0*?VCQ`drn(aT&vddAS={Bh1x%}zr>C2$m?t5RBne(nJ1AEi>$$>C|7lDlu zMaJ{XHT(?UO`oAt2Wt9*sr=mf&i?Tmk}n@Wzam3ntuLe<@V2m4&EO`B z(uKc|#P?fRzuo^ujBv!DmkIpz9sZ)P0l-wn4FTc?^nLq8=|ipy-g=tRyfX^rONTaa{IrT zzrL=opZitl*Nx+L)Bg6XDv$fQ_hEX7t?X-#o^=j(@_`@IL#@9*cyaC2J&uxf4t4cC zPrh$2J5{o-VV0nTZR4Z!a`o!H^H$sX`ZfMZKkMB9ZI+}(%Q>7} z3?5x@=Jy4)QEx9VxShK_HC1`V^#4Ty+Hs#IO;35fe)qdwZ}$G!FEQ=quh;9(w>96& z-~YF3wvO-%uSQVX(qt06nEFF_{tp*WYgc-nJ2-J&-oRugFvA7Ze4CN3 zg-mb%{JZ8ibD{gTHi!3|Pwboj%)L^5{hDO&{)YSakKMl`$XPP`zzP;6xw;<@zckDL zQE)w+nG0%jUj|)2Vw(1D(`mh{XD_v}lj zRlzT zuB?n){M77r&SX|O(8X;fuh(u*+gc2pQdf+v2rOA> z*X?-JwWa9kDU+yFHrXreOtA_Ajtw>v-~T+fx8FTKYqjk6+w6898mD|W`SoSF{oH9f zk&}G)Need|3lP6}`^By7^=I2Gqqk%PT0LwL4(bt(@iAQZXXo>Iv!C{>OKiK9wK~VX z@cpqRc^{wbSU9sQY1(dIg}QZr&ffpy8?`+z_L}mFz=YiAbIbkQO3{ivzlvPUuOk6rv0aCRl7M;O zHc;9H$6AF851GvG*A#>L9apzZ`&e-D<8k@h*0?8W8KlSaamF;xlEn@CC-3^WYGtuG_m978 zXRn{POISj>F_7Qo$<>~PF>FO4#wLe;PM2nX7LiAtyI$PA@anG!kKvvuo263zcb@t`_$twVS@FU&2S~XP_Ebda zf-95ZpEMTbMX&3=?CQQ(yH@3Uu(sDHpRh)-!_K69Exor_`N8`o_jXP@x5S#|&%bN3 z*FAMPd)h%G2*(zG>T`q)DF`4BVStAnO13%3b!5CX+;YxNd@IscDOB}VAr14!V~q9xSL z=q`cWWpaUgaTK}?)JY4(K?C~_wXCqM8wBaOu#kyKP_`;Dq#GRnnD%@D9WbFEBN-u2esYx4Jry8X#-9~bi1u6X-b!vh-C3JwWIToSV~jp9n5gZHl5 zY6|d9@wfY#a%)4Pv;VyLlclr-cu#^F5@mPW^R_OV&XTw9=d&;J|3AvV1YHcc>rt1s z*W6pY=65E5uBt2f|M&ayv*!2rT-mp4;RjHUmQ``lI#Ap0c4*%{5zzgq&+31_-M)RV zJS$>k+Q*I2R!Qw~X!$u%FkCQZ0`+^l+>U~3!n>u{V>Rc^nrD_9Rdud--sG~|x!Xal zt|dP|KmUH_r`1Hp#)@6PljVO$Y)b-FKA=0n*vz6{SvDp$Y}|3@TqmeA5V?`V>CJ}2 ze9mQpw)%BH4$Fh5fg(4jE#3R=miFG4zWGv<@^^@Czf)kUOQ4Z9lhjjFww$;7 zy##cSwR2Z&+0E3KpvGL(_Po0ba*LmxIoTEzwIRXrR_XQF&GQtRjkf%Fc!*p7Op%*x z+`muLw?|}UY!l!2p*6A=v<~>o@B9DlbfdOpWT<5$<<}LUQ(&hb1s&ibpm5+N{Zq$t{ZY!8Rek=JL8&-=WuIBtDub^PB~ia*!9$ZO2tIeYnWzx_P@D)kE? z3iDp1~?v_22K7FVEd}Q_b~X*yUSWvp37h^xJ-m z*m}b9`J7;Lfx>@3pD#~6JuURJsQ9D%8$I^_`?@}uh3VhF_y6s3cRrnVRL6Jv(V97G~USWb2?bL6GhL-~0dPzBPU}YldZU+U3W$5lN}RVSa-{OFk1g55F*KtPuL= z9set+bj3so?K;pHn101U?oDpnK!dQ{PDg^zUgY>5|Nm?J%LZmX4clck(+$7Yls@+S z*34(6Vf*L9;hWXx=Wh^}5pC?&+qGiXe79m}o6l#ABj>${HBCO&vnA{5s*-Ov)B809 z1oz5(QaGYEJ7?0@u8xO~UoB1Y@7VwE_5O8i?qO>pCdyU4SSa#4YG+X@XjWtM!j=D? z#{W}&{WCN_e(P&cUpAy&Puo~0c;EfM-)`%3ySUUQb*#B~BYj`~dr*3W6c<&I4hoB= zuU}UTs$ClAiTv3A|NH;2W&y*GuiWi_T@-Pieq|Zxj)}QduU5WXwR)YD(G$P7MiOVV%xw{tjb=|1fehFGkZrJa) zWct1@OEbT{xw%$E+RXn;R|jalbSh(KBKHYM@PhM%!zJZI(;+2ONvA{4&bnVOmxpKn zp0<6@(xq)%-)_IZFKXF6C!YC2yw#v~Th*6~?w1d>a$hdHojZNr?>o zmc=!xVv_CmJI354M_6_l&if7O+va#oyWwwg!&N!S@aW_thH2F@+I_uxbD5Rv^RNv`Mt_WS*3*H4+q)Jd9ED^ zh?Jf|5{SB+3MJ~iBdhszAuhgUben`U%%1Quk-$Pq-pS0n_vLzDp*2PJ^{I2^=@c%Q=kjBk-i^`9^ zj{Cl=YWKE2L`B*Nsyi7ELr#T!k3Qj!J_&s%fjcWA&M*bRw)u&IY&!5A}(KWOFL$myn{~zuDxtpnY z^)UaxJpZ3b_JQsNu72dwhA`< z__lrjTvi1x*G)$=Li*Zx~n34l|Z+9>wFOJ{e8Agx$F0crMxTyzFM`^gR_{YnR;Lz9-?L9+NxrCiBDG94RAo`KrTP&dfAcw|!rE{&W?q%lfv8M;29zPkR4>E&;#&fy3~M zH;cp~AD=wwy~2yuf$pgNX7cI(Py7Gs(sH0eE6^<7^^L~7d;M&uGHQAkxY#(#`up$y zx;8(zV$O=|=KDVO=B)X-BLB;hj^rbgZ%tfOe&GMV`~R(F%kLCAGfDmQOYZqOV~@2| z@8WXjH|kP;+0{WU=a<|6eVL>5LSwc+n_Ta&i_*%kgdQJ0Uj3x|*dv=(cauK%doOr} zoFBM2XME}EXgfb6#;Ph@gjw+Il#~6}-_)9{FSdF4|MUF+d!%@}mw!F1cg_9R$Nu^` zv6su{^XX>?Jo_E^tm^pA>ALcbTX)DWc6V8_LtN>G#NiD`cY&t(ZvLH_tMhTcL6=Ce z*_Cf0S=(-N*ti53R;3>O;B%Hq@ZxX9eZMCr?Q6g2b<}g);_@p6n(I8zWDCB0s$c(e zLcQ>*n)`?JcouJWHQZqwGdBlu7^%TbR_m{6C}U+7}Dk(;n|| zSH25s#(_rK)BN4s{X6{YK245n&a(0RQ(phQJaU5)*HMYr7a62^rwjH}9G1R!;REL@ zjxv|7U;7@*zCR(A{kV9JI}3A?(VZLdJ)H7;m0v9d<&4O?-)^SQ{{ot{x$Vy4yXfKe z8Hd!F*aUStl{#=xDN~NnKrA zRvX!Dbid!|y7jqalT*(fJ2v$GR$xjkj6d?^l3>S)W{$0SYwP+RME}e8_-K98>!(DR z&b!7R@62Xzv3l1F+8cE{^-s0oor1)*GS;tT@9*6+-IYZ&?#m)^-smk7J64$M1mAog zE#daTG%oOX&5a$2+G>avb)%2>>Fk!2BNvPmyugMw`RpO04+ zT-Nj-JN4(~tBPHARnjKjplz<3e~B@(8Zz6%!H zKKa_W=c7o~yW$@Y+xfYij(mGz`*C{x&*?V}0zXc zX6Mg)dh-8uznOb-7JuKk-x* z`AN{`bo=*ChDe`NGWREY2y%4)ehg~&&N9so+qUlR|D#(^2Ftmevfuvc-l-*5k3M{S zYwnU?i{<}j{90cBYxx_|@1-m}=WRZpS<@xBAoH5_>I%6^1*K;Oo#DA!ziYLn#B#Iy zAH&WJ0#(AbOiY6NIKeHT1>P*5md{+g>!{m?iDCP11k@i9bT`qF^Oto`u3D0zQTwP< z{nfMDkKOTe?tNWX&U;hLKk)bm+sa=*j@!>;RsMATXEh7kCy~h>=3a)!eh0eChL#s! zNxbZ9es9b-sb7S z_KGIkw&X0;t-)zK{`P$<<@-Nl^@1{q)hpb6?#*6aCY^d(YRm7x8r6GGPwSUct<1Vo zAZx8Y@gt5r3X@n zYmct3h(Ee*#(A|WC0B=ykzEf0RU|3vWO z1oxc$5W8)zkAL)8zmw>W%(^16@3>rb2(wt_y<6Y!sN1g>)ecLU{N>ud=eAmlYA&i( z&2;HXIKintX9BOLam?XN>(ounCO_lrWCTYxm+hC| z8NB=Y?wp@9PAdd`@zSbmXMY%C=OVDyr|W(GyjhV?E3@uDz9nCB!SUv+AK%sAn@)M& z{kg+3K*{xe=dHM~%6$*-C13i=A$II_{=aAWo9?+^3|47sH%u)3;?U)}w|nn|tnV|w zw{=(@m(l$ibn|_*p+wBH`;V(iHzOJn4*Fa(loyGwUsVhmC}^A~a--_?+SUF)kNsga zR0*`!%s0_DTVi_4|DJ{P?PQ%V5}PtrG~1?0>ODPd?z%6nxBKv0_4k5;KNqFDo^ikE zcdAxthTvg=t&@`Kx@=sNb9uH4_bv?V2Tk7IlwrDPQGG(O{R(f(mS8pexW(W9*c^Lo zC4T&P{uSw^fwrH&CMQmKZ+%a?*1ibTyt?_RP~W{P!Ef_CtH@NJ z8S+om?SFcf&A;XsCA(Mj(ZAkf|C{;kcFet-o|>ews)|qW!_PD6c9ZW0Uym)1y;l74 z05iW#(VQ6p*3UL|i0n=2`rjsMJROo!jwVN_AzHTy4i5btjNIOk47He5NnqmgKbo)p z6t8}7SXgo|Bd%uA{=lC}$AN-S7uDa|l6f;A$Z)&s=Ifx2 zgW}}p$8LNxJXvZNnQu~be1g&c5B&cpoU{A=W>;wTa-X}hp<#YcO7pH{FA9w9e(ipF z!H)Y8d0!wo<9s!vXtmANYqchJ;_sij*|xP=`+Zq*qT2K6?Qrv{hJe=3!;pJ>YMkDS?gE6iqoSQVqm zs`M$nKP?`4zWV>8|9{4m+#6pFHA{K8iy!xzFN^>G>-x)C+3P$%KKTL~&R-L_=icQz zZ>OvbpP0Ar+~U-L*Oy-W4*XU%U01$%<&h1Z$+mm^H(vKzT|E7Y)UoF;ZVKB9DY>ri zDBt&auI96y9reLVTR*=K3fs{7|7eV);ES$#;-IO=yFx$b$O_)LnZ17Rt7n?)a=!l# zn{$3yM)aNSsYru;Y%E_oBsOe-`Y>vNg-#HUt&p?o*2$j~yB8_ywi#wl>$26K_jOIW z>1nHnx81Uh-rrH5SD|Md64KzZIFpC}v;Y4u{x9eM|2aR{j_0am`kadwR?jv1S~hLI zyLsI6i$)r|On%ip@p~Khe$&&>Kc$ocHf3F1l{D48bmxtTxEvSxmySvErq1ZG3i64P zJ-BtxbbprAvir5)C%)VC^pD|tmpcBdufK{MoWt?Mwd>@Q=(nkt&V64iaVB$VdE{wz zO=U#MB?r1r_#*e~EugN~g6}Lz91AjHxYC$GE&wHnS{lvFj@BL3f-noX?4`(dR zSkUWs$K#@gU5tRnr>((ir(9oMdwnPTcjN!%J;oh}V@zvS)0lWLl?Db=JnQ+&* z{JgVw$NCpDC*BV~%zHXSCp;$a>+fmo#gA%~8IX@dx&S&Xd}se!a4KD}n5EC^)ru_V zc$;1sVMX&<8m7l``_{Z9lZtws8dsFJ^O((NHD<*UuKd*kFxAf>|?Pr;#mQul=*>2y+zqjFL*3X(V|Eqp} zu049>$i)S-mzSM-k}ADdTz1z(tLdg0-yvyrzWJ-;r8ckEY<^XDU+Kk+?^YQld)uSs zg^xcko_56c%DW|x3g^stVd-!9CSpm(1pRgAxA$MGJ`?zPZGP?QUArZMR+=4U`8ZK2 zL+Y@FsdwtW{6hKXPq*JKyDhQ}xgT+sl|^aR?;DUy1gyLi)N*V;olss~y6eZI?#qS8 zWv7FuRZpr;Pua_~$nf3o`~T~H{oeoocM0ecY2Lo0ifwT}4v8-Vb>DB=z1#Qu-ItaA zwOX;&Z@1o@BY5$En7{e|=k@>6tv;VI-fZ*n$hXyTUst^{R4-C|^?UvQU+W_m=a{hE zE4>~IJ~Njf6zBaFH&X4$iF7>5H zImDC}Y&^_o&7&pwf7y{eTB*TbxH|92|J42$+x_|f@%lfM@`%xpioJZk) zx2~O$v%a3u_+6{*7ZPitTm9~oFl=C4;6-X{w^)aQ!ZK2e?+*n#EH*aKh68@(6#61e%Ibpt_(}=)z16g z)=_jcPVMWr;BUXh7}wjhu7nhzprWVYzz3!(q`t02W9_$_>VJRl|6gq;a;kXV=Q)av zO}^%LOB-OG+944g3Jzb|I_^mxJ>c=?x2t|tAb28lk>M`0tx?yL zcFquf44Tol`gS9Ev!(hWm8z*nf}aR>bciIslP|lGs44aPv&cHZ9i7XcC?Bua}nbcKy!!{#)=jC|r;0N844o{JFjV zZ?xIQ%8N$t9>16?eE;nu0f)2iChzh4dJnYv^wq1Hf74%e9da_c;+}PlTlpXFsr|e!Fe8 z?U4oNQ}^dzl-BZhy<9W59I5(h|#RQ`@P@Odf#4Labv~74Ljz~n5}dwchARTy#1oR-wowz->koJAnK04&hfgW zGrw+x8y+?MRK5u)oPFY|wyK7f!_vy7)w$9jJW_jv<`Tg3P z!mp)sw*-o{oRCh;{`_oy@{1KV9D=;_1$Shm2|RU+N?Y>WH0-+NE4kl&?-PGa@l-aH zSo_{RxAykVdq-=hXv%*tuql*3*mi54&&K-|Qw{qVqQ89V{0myayZ-mwo`#e=$rn$r zxVcxfv^Op?aK2k(OF?F7z3btLI>#r32`=dP(pSDmdGEKa>vMPh@Yt8X@$!fM`u0b^ z`djm`RXi>7@%`CVlOxP;pZD0G zZ`kh2qNvom6e*)QWHYs;Wu5gzI_W4@zuN~MGEEM2P)IU@%^87&4K!I7u^(V$mzgm4cj@)m z@VPE~qYW3eJMr*~YTB>gXf<788mI}kQchb3`DC^zVS$be6c^bl7W{bFp8k2)kqpfl1_w)1f`T6RyL0PNUZac*! z_&9JbXkUjbL(=ZI+q`e*Y(85dbIA}~NP!1Ozw{iK5}mg*)p^d@M@PG>pDme#Yvn#@ z6A8ChyafsYosKbI{xctbH@|pw TN9h3u1_lOCS3j3^P61G literal 0 HcmV?d00001 diff --git a/doc/images/ldmDspeed.png b/doc/images/ldmDspeed.png new file mode 100644 index 0000000000000000000000000000000000000000..d5445f018adedc0f0c0ea7880782bc0bafb35c5f GIT binary patch literal 27594 zcmeAS@N?(olHy`uVBq!ia0y~yU=m1A_yDr;B4q1>>8$)mvmk=c<30tFF?hqViCbX$I%A%Z@_K zyk{2|N~(4kDP&~3O}r>r<-2*=e~Gt}=?tw~=bSt-DNgsyrI~UQueCZW?~|NrVWZZu zOu9*t-%Wu(*~!VHLqKR!LuKFYV^-hq%_)9oX=%QD((cbIw^}Us3w;}Z^E6D6Y@3;)LjwaN6AQ-`7Pjfd zlhyt8()S936f!cgNO9@J@7oh$x8Y$FHz!y(Bhy|E4uQQ7B3vPwOvD5fq;^MmL3m%3 z6db-ZC5wWL6HvGi;n0xrCP@>@>uzAU$lVtTafU-OBjcit-Akc7eI_OseTy(bh`qh6 zEFH)6rU^lK18$+jor=PAZ}a?nGVgXipSL0B=B9$Hq2aCG`g^xzF3i2XtyTWthxUgv z)8}zYo9FQ`v+;1K&#OqXc)#cKq2Kqu?<@Fn(f#_?yW8{QD}Fp|KYVGa_u(#4?XItr z)qJ^()6Q^gPCL8mww>OKCBBE9#GrmQZEO}&cqISQUB1@jPWk=XhrQ2^`ak{u4Rh}9GUbspQkhfvY^G~N#kZU3hs*c>zPlmg;-Z4rYqz%@Y~Ib6|Nh?I zhwpa3=llHZtoEsSb-!L7{iW(Xt>tL9cssAOSxff%z1xoKS!Z5e+`tcw3g^ak`!Dc@ zZ;#uNdU{&H^SR}1&*#_M%_%yi`EW*ZpXND-FV~FNdL`tR`OX%z`}@+reW7!^*zDsM z3O}DUZ;$`~>-xh^^?4li-_q;Dv_C&+<`;XIcxOkU>kbL)vYd^1PftxvJU7QO@!g%B ziLb7#d^o50+{@tEQOU+o+k+eJ;+X~aH%08ND&6sHR`#LX?RUletlw@~X0085WWB|s zlAEd1uO4##Q*)>Ac14Ci==V@tiW}|NJ1YJjlr6s#_(xFQBqQLnt!aet`sy3?QJd3zH)ec! zadB(t>aew3udlD?KQ33DGs7s=E4R|J_}$LuVw?T#|CZd?TU~B=-*fh+dF4!CQx}wj z3>8#%YniC*{%zm%zt`r~e!F>eQhx30=!ajg$FE=88{cg6{Z4V>jSYzp7j^5c($#l9 z`sC!~?rha8?SBTwb$@;&{X93<+WC){s^8o#KbhuaApS z|2X^ppJh9qJxrGW9Z{%$?CA#@3Vt*;`i13JgBo=44flZ2zUIS82hxugXzeJhldZR+yA~PaNgm_ZKKEG3WZh= zTZ9kwn%|4KbMB_>LYvhB=Y33OpW-%5Zs-VB&z*I3+Z=G2A@D-8z=O%frlmqVz2=|u zoMSzb!f~}h*Q8M{D-PZn+t9?~`Qy-5#(> z?_Pge6`UB~A6^X(#|vHy&R=)fa?5e?*Zse)uJ1Ay__&i_{{N5ThwJ~Y|8M$d`u|Vy zhobNQy7uT`(EQ(bo*&v(`Z~+^@pa+CTN{(zb8r4L{`jliqF2gvRmJ-yz85cWgZ-*- zA!xxT2EqMF9gT{11+R?f|MaOiUwu!QjZa46-lu8XTcY!JF0Bws-Bb5)-R^g*WNT`+ zxy;#?e?KnzTCLi=(i{J0wfo&FS)Vx%;_D2(fXapr|Gu8`xIZ7|{})!=zJ2f7;}ef^ z7kq3wWpUI!bb8~$Jxe$Lj_iEL`#4KTf=|@SS0>@LO}#$JZS%FE1BA{kXq$s<_uN*4bvc zT>Lg495%jt)UB^~@3FUfZdUJESc%TX^W$&w((Y(!tG&Sr^8|N%zgL}Y-N|3jRe#0b z>g5t8mLsCV>V7=o@wKHJeg8cEZ(je|{3w6I(ao$M1Fw8s-ScCs+n=dtBlPFxc5JWw zcTxUt;M%;JEv0|Xc2}@Hz7p)OTlf9ZS@Zim++sQ!>y~$Xwg0k^|LV4Wz$Y5Nw`bp#YqtC657;}A;6!`cs=p*N(r=Ml2R*S8l+!0@YLJPMcjc;;}U&)hAR6Mk(|1=phPlN_Fk z2g-Tw_ywsEi$nz!iew}IDuHD=Sy?(-c6fnn*TxuDmW~+ru>D{w9Gn;#l@!-q0%v%I za7IR@>l3f)gF|LQfJ1{v$7&OBIzAEV&~TzOSV&kF+^UO<243dxa7-U~t zBX@h6yj5oKwy%ERl7_=X%tC`v>EFbE&lj`5@5=Xc$NzaG zez^F&ZFo-EDb3|A#pf)Sa|n7*)8RaC_dBPbVPpCGdj;R`mbX`aekOW*e%-H^i60&u zRLt95@$u1y#KUa`Z?|6mb|Y0iw@TzgBe>TM@Bdx?Ur(m|PT^Ly+uL%vo7s3*)%F?l+xotS2H#d_0 zo|>wCc#dW9p*uT^4_{ds+$|7f_GXFi&1=@+Vpico%!2dR9c(_IF;4vY>gvN;+3PsB z-z|%_c)R8DtoLvEvmeR-Ri9t8iG$Jneob-z2Lba=#grQx5^Z1Ee7li+^tp82j)h`! zkD7jz9)CJLK5ory`}(?%ar;UxEz5a57wRLu3(pw@*W2%S+-Kco|LFI8(~NDm-Q_Bm zM2N1Bmawa-*nBqYbokn+&=}>yHye+)X$CL5GHtr?^Lf>IhQGgD_HVztyIlP9+%1}~ zE7if33rm&wi{b_e!z338%c7L`)i?8V|Ljusdp@`PUR}0SeGI5woAl|)$;1Ny_Zct>SSJF$$5>Ztg10HoUE~0@M{bvRSxrcg0_qJ$8#Gn?3!<_wDzm zr>FVLJikIJIsV2U@;5{Mrm}ZPh&(bWcyQoD{{Of8b^kp$e*WVbr#-Wk{XRZAUjP67 z|Jt`v?Vr{h`gh$`MEd{3)E5^P9*yA&5iq~o2)|AhOpi(WL3#_W( z-mL>axS_o`N?QIDx9;QXeDnW(S$;S&eXeMq)vFZ(_Q&nF)PEGO4-EOay#Cj60cW>4 zkD%?&kM~}v#{Cyq9=O;|^!?l|no?EJUUd{#h@3*7-LDsq7Ce${`jq4HeQ}TfG@bqD zDxOXa?+X36?VLsK{e62Y?*CVXH8bDDUrz_u{0<8?Iy_}mvNO<{m)j9sIrq@N_ON@I zfo;7P7rTqkUK71N@4s*N`HzdvRQyic}Z%gcPV=lMv=hwm+XeC+S+mR4?YvD4@5|NnUu)%9cHWV6y% zT}a=XMGEBpM}aW~2U(9EJR*Ng>;0(??nmKL|3C2m4_LGN$t3Tt?>~eNANlg~a`*X< z$9J9LR(;&$JKL<4U9Mt5MES>~;^OZ=E}d+)^;jA>4KOsuv9kU7C&_bk@8r4nGzHFc z+^K%QckA3E>=sAuU#ZV637TP$=(N%1-@T((!{cLbtHtqDp4Qzi;y>L6)QO0{+!G&t z#8_x!+#lcG|6k_+3)a|wsDt9W_?#@4B+Hak@fBwk)KYiOPj~x#=-ffWlqC+wD*_oLSH=Wjdy)QF&AF?my znAmk4zO1-)u)RV|F^)xYf02Z7noqRoqqlSQ_kIc5SZlq1sbF{6rDbcIHwuEw9E&EF zQw)JWo0ohu?~4!K@|k zEG!)|Zh`XP5Oz4q#N=}HL76)^859W!C=^M!)n6o2v1%)qy@^($f(pFcm>in57^ki5NNpLE_igNaX4GX_WVNU;l2Eq?Tx<|*t;Be zf3QI~;?vRZa%IP#G;j#K5Gr6>bo!7CI1&^tENfu6s5a#+IM5jy^%xmP$g5U z+}`eA`zrY1kH`J%vv=p;-}m9eVgB}|-qYJewZlYStNYFpNjoz`FzxKD(CxJ`7d&UT zwd$xqS}$2l?5Yk&>@W4({mR(!e&6py()oJ=MfwvL-F?}}F2~_LO=o59zhAG{UuW&u zTm8Ll_xpX;XJ(tPzwz$NWqx$HD zXwzX9*O#AC9qIEb)z-xAwTdY|Yx;28?L6%!hs%3SBS5v(W)8mjKaQv$I?#BQ|M|w_ za@tY%3l8&c{U9Jdr|_8M!%wI6^{<_sZ@<4nKOUv^E}rpEe0Sw+x$H+@*~{+~x_@-9 zxv;>|_S)880{g2fe!X0N*i}4MWSP&*OC_H}SBJHJeSN(>x!-o%!!l6o^P<_cThOu3 zW$X#8(8ADp!Fk4{BOQW?PfkpA_SI@1o<=y|Hoe%WpVGD2)Z~|2$XT)m(Kt`kqkT z$L{zq76*(Jj_fvm6e|vDv*}&vIX|uA^0&9Qt8?P(I?`po?SHm#vRSGvY+(C6(^U43 z9}iYoOm$pz@nP-v-S>6H;>+)rKD_(Bu3W;ls^nwk-Cd=y{RIyX zJ^K9f`TY25iBM424ce{{$j}0fmDb;w?Q8$*Vt*Gy;kTRV?e*Wz|BKAs{G$}yaBTNG zn(qGRYyAIGU5%VuTQrZ{ztnO0sCfLHo zJd47l9lu_!KJ9B&HQ%zQ z1!>DD`z$!msPymEGyVFXr>(aAD0Tj$?)UN0i83aaO6|0t_x8S6xqO~f-p;4f3a-bN zxBi&%3N+W?KYxxvqSFk^;!goYdUf8};%Zn@&|cd+4yt@0N^5?QQU6QKPcw zf=}$8vZG^;;1XnXBz1Ir7}6^m9bl*Kv_a!xC5Jb+x9ca0PgR37i1@Z0c+ebK@cG%< zhx4l6ah{&0%N-tD8oJ}lC2#3z{f!T&@BfqfZbyr`FFj5Olt=If-MDywd;tNZ!%(R>M=f1m6BoliW}!f89} z{oUQ>cWS@i-CDMMeqEJ>O+`V(rWDVJJr#vFHY7Ul_;xG%_nl?#jF1jALt`6LEuTR2 zwj9p#dzI-G|9(C{ths!SP@m|jg4Mghdgqy4AcO61X@k7I($9f^_XJc9dEbYK9sq9?zNKir(Lu2c4^*$H1nqW z&oolq^S<`Iwprx9n#zw?op;vO)W6wyysLj>tR!goaVxRIkIihnS^JjfWrIel^5*YK zdo0;w0UpY&{`O|&+K8=Lp`fwjj`;E;3pV~Q0ZoE;gBBBPsQ&&gY2ReC-`Bs+gv3;a z&V}a;hDk>{9!a$wd&-~lGJE~rFq4k!E=OKVpUONt%k=1*CnqN#ZeV0Sb#&|ZkB^Uw zpDurQNAeM*8Mtd|Nr;CyLs=UF6~!(NA7IR4&SJE zPw!Ta*8Wc&+pCYQoNRVBE84HY;VV<<|LY-NZMV2H{f&MwVSZyr{fGU3p6ZK>d;SB> zhW|0~IT+mdZUDqrdM* z(#D!cM>-$ATD@NH*<)GpkM0{EiL5X0uwQdE!|L-Hu0>PKe}G}k$quTx&IVK zrF&hH`8#|1SM~YN)0uC#v;Oy|sJ5b?=q%`qQWPWc#aoqlePq~7i~n~E;qs#Zsu zPWNSH(}~`;recRv{jTR$ZT-{Zsx*5fjn#PM?e=6o-?je565sFNYG=;>H*;rg<~rR* z<)DO<;`ggvzC|zRlzGSWG&t#Z4cnuD5|g+9$@4ZcC$4zTW?q>e4bB(^Dx5Ntx;6S$ z5^5n6&X!yp0+xNN>>%ygBTP&#NeNHELF&-Q#N^Vqc$GgmjukdGFiez)s05obVQ~Y) z#K$XM34=Rt9y$sRDr{kpDe@;83Jy;!R{e4Tj~)tfa|m=cPK8V`j9N7sfTPKxVFc!@ z0}q;SuEaWY7gcwEU+u$(?ecuy)Ae|@!`5hQn{ARAG{Z32ZH8%f*x|C!t(iNDp=(DQ zXB}|l6!^&hdvU*=)Vtm9_kB1foiB1Uc}9lWTWA9<@!p=wqiV}>G}5X~*01vIpZg2a z`Xn?Q_m-bq9l)kJPT=1&CF+} z(bBx%#pi9eM|^`%>xOP!X)S>?BE~16?AF7f?B16XvFG9;)9h;^-Rl1HWY~Bl0=A$0 z@$qr@Q|t0~JRe_Av|KHmWVVMz3Os_?7Fr#-qxAK)q}Ccf?{VL)d|^N9qxu=);KoyAY(815EfM0( zE^}681;07N4X!xAi|UL8K*OATTK9h4%<0-*a!m8yF3IJqZi!fbc4|0~s2K3I-d9#^ zZkYhfuZa#%(-j^aoeW;67rdd=?12QZdkh}bZcgX1EOg(mAxbL^0L++ zdpdsXc-1Ryeogkmp;qqh)aUc->m)2b{Fjdl&3(mpj0tM}LXh>4M$4mwNBsHN7te*} zW?7p!gKJ2RFIpF#?>2Z8*;4&}@AhqzKP~k4xBHn=@$sm5_fy!Sx!l<|H>bD%*e%{I zrpsl1uOj*5Zt?tmKhq*WO_b!A!rOo62StX?zU7EWfjmF{`sa&(4=$@Z9r8zTEoeoY zZ@EDD5&2`k-lW^#PM-b4;`Q!#yR?rS4>^9@LttM-g97*{=V-WFIV>oz3^vx>U{5)jKZ&5FKw&8wIH`p))s|s&3v73>xM@| z2J=ZZmT$rW3g4JNPCSsP6u{PDSKoT^`oAOGT90S8GtXR=RjhD41>Q0VsS|uUv1Rpo zNP}Z^5!>j}ywMRkfzcJ4R9^CGp~G}!U+r(9vcOD8q5U9%o5$`3>+QAMQ%+9$FnRtT zl{NAE?Q-tzv6LylQwW}k1Fc-HcpZKJ)`m0P`uim0s$MMIkaVGb2toL5yCYR^Y*O1hlK-!{7Jy`z<;q`&ntussH!WRRJ`3)bYRO z*X8+q^`F%1gRDO-r3jpCkvzg{PTCc{2GIqCXihIxKm#FmV}9WR&7KGeb~ z{0nucX)1dMXeS0}G4s)bpuYFRGsfrF$lmzA@B3bX|2x0mtFC70m}^~r?a<*jH#Z*^ z4UZ87jb)U*y(PNu*VXlHKR-WjUtjZ7`>0v!M!#EAa$%cy_Hu{R@g6xfRoi*bGsU{E z7i?{g9NzP0)9J3ocXt#fcQ7uPBc>M;8S7FTVNt-14}c zE53mi2DWEjUM4zUTqhzR`kp7!4v+PqDXNNVit`LR(v?7Msapq+u2-)6^H^Sde)`#2 zq0w^baTO0+9~JL;xA0;}-0uyUmzUjog*-7@CA#8|R7b`3qw4lQPkylfcl^J`y7-8F zHI)_5t?x_j``DW=BJKs+eDSbZ{!c=G^Sw=}-XAML6O+@X%O{<+$i2O7ZH$OjW^i^+ z8$+YBp1}Y82VEK*elwl@r@Z?w7yGu@!F^GvmY7^|fm)xC7^Pb{tf^ zcT7@$g3j`{x3{;0mh8*7^Gb*5z57^qCD2`T{$p7w_>3T^61*_&fFh?r_4jwWdKEqO zFW7mdM8JcHJqJO{4ngCUdV9ZIx^?jVy}i55?!Rda-sm>x)YrLNR=z#L!^ng_r^w#% zX7zCOU<~sJ{OnVV%LquU? z>d&1u{n!1Eto+lpc(Pfl?t75S92y+58`r((ipsAJ*!JUMe_cpRdxc?Y&5z3`)#t~= zghkF}EBeo&n67mybU_4|0P$D)*9^y#i2UtRyi_Wp?JYoSR{|_;`Mz&m0TGn4*)a4=1|Iac;j~SN-wHNnt+=#UsCuJk~GnlQ!3j zssH=cwr@SkDgsdn&>phd!rZCbeU2^=sPFw8zW-NfKXZ3^;GXY$-}An&JYVg!c)i7= zSSiq|-5+oB>!Y`5*H1OJo3ZNm&GvV$)|r?0{yjJYG=jvwxJQbmPoq&azUIB))%dxp z7vfn?weOLg#1N=-RQ^oW)2ZQy-q(HKt;BF7-C>LI(bpP}j8z`V%JkL+FAnVWyJfQK z@<}7cMZ%`JeI<;Hk39aHJN)MlZ!~fU`6udDKHL>ubtqeq9P`s zAjGT<*#=W2BA`$t6Iu(|AkoRn(sAU#Daibd3@b~AjC<&ONFySNkx|KT!>3WJSU5%l za401Ui8(v=fs*YDj|aEC_g@LL?&XkK$s|AT+e)w9?|596-YIhf_ar|F2q=7#aNi5* zyHDlf5SUtYTN09goE;iYB+Gnl0_UF)Ed_^=Q@QDotiaF6sMKG0g&Umf0#-IK1Zr-d z3mFZzVPWa8ITol7$v{h)m_~+W5;YpTKfYSMz75o*dU$>RztW1AOQ#=tcX#(;PxZMX z_kNx$Z#%8Of6u!MaWx;0ez@Sw-zusd)>8WVTIyc-(xhV;!$Vm?c=O- zx1h8KPcR(;t?K#r?)^W#H+Oa#^GKWN_{_7hm%z3%Qx1Y%lc_QV<+59@;f4}Sh zzdtJ3?qBz5^26BoRpFq)iu&1`K&#68*+I-#dK>e5<8!SE>l)k$1;otZD`?vj_py+(4^m?p#8=q{{oShx<;ZuT9r);$N z1wcCsy{GHx?rW>~zWe^&-xvQTz6Fg|B)!}7`P}N;|6VNa=L0QWnx-GIVZk<(HPUgc zTKod1r|D|*y?C2nUtRcY!S%(z51$f`t5`Ur`?{yetW(+YNfw&RFesjJ`(^DuP3*t&?$C{W zwbeH^r~7ZzySMgYhSjSTi@T1dz6DjC*^un1a3KQJ3IXj!aNh*l+j7?QdP_yD^PUW& zd6tQb*Dx?>CxgxcFa)(H4ujhDANc=&;6FOEqry$ePI}RtQxgK~^zO6sN`;)6_S!l# z_}VAvMw=~SpqB2Z{=cAo^T9f2Y#0>dT7{2l?v^_Pou_*FNX==d%6Z;KDB- zXYxPYl6<_cXxs7XJ&Tq7o`%bS+E^DLi?|&Ygg2gIcG;7ya`liSyxs(+B@0I)ma~0zBD*QgWBuDeijQYHhk)@+q_t(*)2x? zyx)<`x3{(){ryk>>1X*}_UCp@MwtW-sBEzK`{i=Ca^*C(ibTs#|?R?P0opst8(kKT<5V&nucr7x$HM!r`47A(b z=F?Xi1!SpHwZj^FQgA2#3jvG)ULzlm-gi}t@=X*>cSr=9Ds`?7c|x6Xs+cwt`vUoe~p|xJMjc@L}%zn&lM} zLTYA&)JzDeX}EIS{@+J~)KgP-G56W;5`Dj^;?Kw9hlBlXL)Y||N1vHtsC=aK?s>Z@ zz1GOPti&Zg{C4*i_b%$+i`&Ag0EcUkiO-S~XhZlYsLYx7%vxpNWQqBo8< zuLaJ_m{?T@zOu zuH9m-pw(GEGYl41PriU$H%M{Gd}8?cHoty12Y>yq<@Hja3agEMXYuoMQ57?6tIKvg z>e4=Rppp6Ty4c-^!uS8WYEb|0&xfh&YnI+vrgOn__NKLnQ%0PtcwKC63!GN~9sHum z){%A@G^1tAAH3X;_kI2U-`yVsw#yo&c-C`v3!M+oGR=1S)3q41$O*oM_lsV^ z2`11u>LE}isKitANO=B>uNw8BQM}jZt>5q2^%k@i%pmvHmZYCetlU|kb_r;_3|cim zn84aG|L>dh#HXjGKD2#b>2L9LN^q6!2~guLLVkU9hRM|Hb~(4UtlYK>d2w4DXr&N% zncTJQ`$XM(r9|yMH1dC`YAAdPYO&?I^~u~Uxc#`#dR@f6+}qo3{X!l0vru7twEOC;KtI{#&{(f6@1Mcemy~Di!Ws=Ge?8+I{*fsOq~8t@F6$X&tuCyrv>j> zVB`ndqP_peQGKU9>lE+Zv#j{=;L+-C^LrJ_Cfow+_kN4IXciZY;cO`d@Os7tkA#)} z->(0i&&zLMcV2Owv~5*M?raNrW|u#|9&fqqw>mrA?*GEykJngd28Z83OlK}-eB}S{ ziGNqSy{XkC@aa4c+vW9`zy}jO;&It|_h$Nh*}6}Y=Yx*~>ekz}A|__f@%8%CbRvUl zWQz{6ieI@_irQ#i%BWO#^h00yp2ZItk1qE-#$cFsX2!1ENBlWQ83g4^ZHu3s5t#20 z>G%D9eSOFF{A25_kM+q$>*>`^dF^l;vAv~AbcKn-mnxOLYvzC!@IRU4eMq_AMksIp z-*1mjP6q8X01fGWJU!>}v0iS_DKhZ_4|X{!H$~vu&yl556;**T1RcW8si# z05z&!F>HHRbGhQ1ygWIZnSXD2&b}6!>j>`S_xUv5 z`yc%OgvrHhNc(C*YXieYrW09EUYtY23iFLE;BLM^hN6PQ7KTl;AiNdg0t&Bubrd0M zAEG!o1auqLK-b~EVrA*567~l7^BEe&n3!C+6;^{6fiW~zF)}W?cSHzk!KiiM@@q6O zAx-$vqyp~bE*Q;s;NmHYgC}pJ-N{#=rC$I4?*CsNv7;dI#*V^d38NGb3H!Pl(4MD{ z=NlNArQUr%Djv@RI*}=2W0Gsc_Pp4OX_uCGK0Kwp9(10_BggE^8z!`ZL$|@f7j*WP z^MU7f-*&*@u?(~Lpu-s6895x>j_wo0q(} zP;j^Odh6mot5p`aQcq9&YVqnvsJjhfJdK0Du=&ST_Z;!t>mxU-9oa1X^a^Uj?i91j zpIb`*9^S9-0-u?8^pUJ}*_VjFpXdMI^P}co<@2u*a`rN{UoIxz+LC$n6Dzmam1`IS zT8nO81Z~pDxw&a+gl*ZI8*;PvemKN^^m)Zy=fx}cd`rB%%y;Y6xm#A6n!y(^72IIy z__6iqw%prY&2tTt-TIsLnvb5Cs9de1Zx5P6KbmvXuI|MW-^lZ@(@}PV>fU{y=e`$l z{{=bo#8LYa7g;ZWaD$)oD?BX<1?-Z2eywQ@d+J$Mz(v zr`GF12fH%D+xq=(U3m*{F0DME$Stsb&nGX?R6}y|8(3;@^l?@&7&PR?19bc~x9-8j2|MPgS{KNOxL9^gT&A_Y4zTHf( z&Z!5_UDh949#XcydNF85@i(L~z+ob~;?H)2x-X06TR$oKfBZWwI&Y=*jvv zH1hXp+UW|H)nRM1suF(38~i-!U$<$;X{CQRu7O6cwsefFjOf0)N@BG>Le0QypcY}j= zBftOekk!6?r+$H&R#WFUT1dFdLuVo5MrR>M=T>V+XN(<2r`!i zZ}aEF;l!7hmL?wU5$PgqSvS%`jp?RIdxkVD`_tioxAjcI3RExJBg-Jg${ zjc0{0s6n`~=J~m~iKnOOmcE9a7*!>H;*(SdXsg~{Im@Dy!}s{1oAp4aHT18ykTQGm z_|W?p`<4BoCh7$$TtDugooMmu*PVKnO*YK1a~UQ|Se0aK)MMj-Y*A7uNMMSb*LY)V zcKAYp`OFugE6v}{tm=wiIs@GAb?^hJ=n(fmmU+BS*7vv;^f)flyT`boo!^ZP(-apUHki6+upu(*{E3ciyIcg+Np{YQX4>rBwXBC`uduw%(Ln7bvt*|8pkPLeB*Sw zjTctmb2aKPAK8+5`OpH#=C0$R`FD0~%v&L@7Zagl{r}JB!v`88g|2+P2^oVaFks#E z=e6YiLo@7Zs~(n|xBdQQM?evL8(eJ7$D{0*gLJ_zEI7iEQYr2xvlsVj@ruX2=7+9^ z$KU;+Io18liPsw7?(BpHMab&=%dAJAFrMJape?YH6IS+^m9DZ zW6L7tZXYr5hp36$D1MoWYKp zT&FohG{HyPfOh`QwJvYtuYKX1cx_E&?%TTW@9sYQb~~Scwps40jekKyz#9?|A2K{H zBMdrQ=EL#&KgS<}4!d=3=X<;H?mzi&@9s*2rq(xTwfb4p2X3S zu4R^YCt}W1P-peWjpKGhUw=*E+RgO$w$IPJp0l<5pZ{FT z-*5I_kISz6eP&*|?d$#XzW&aeao}ZupThaNHF^flt z0ORu+hRLs9ahDsM=_o$jz5n>j%gcAKTc?-V=H#JzNAI88lnn>7CUN|cXKJa;zrXJ- z>ue6S`}^zPv!+#EkJ(X>xF~r?`TKd%`|D~K1~*g)@v;Q+&*3+bFcR$WWN6%UbBX8V zoXyYXChnCs&$EzupyS-Ir}}%IdHugXYYyKlw5b2Lr`+a}y3ZVoi?X&=Ccy`OzP)W; z{_c+D`l}w(9~;*@TbI9+Df|`^7Wp>Yw(-xp@Yk=yc$F@cF@0&N(3pAgv!+p1tajL% z56c&1JNV2@=P;-gNcNtt_qEUc-p*V4OmCG8OiZSPY)v^iDdo1A#3}3QZ)?isW;{Ey z<$UPsu%G)UXI@_R^Rj>fKOf&N{rG(m8=uULRPd=)dv##K$y-~q?@rT={u7e3Y+~KN zKR4aQCNb?d7pVO9{k!@(&?=@o$9kn}e@Yss{n-5O{{Hu-G93$2pDHilaQXSJGwMnb zQ}A*>-z5%EML~_R>brUVy^_O+5ATyaJx#Zm z=ke0smnU5~&2nx$n9Ek=F+>bGeHam%#z>*Ac4 z9v|=bk4hD6PH{iSwo}<)S&LD#a<0nThYLG2e@$4n`21T12NT}*8R0K%0?a2GSA9;r zH^uGtkqz@L??!swJCpe!zag>5?ajev_LG@Bl_`?vn4B9W_WS=TKc%&}_O0py4wvf6 z)!T#wetdZue2MEwVsAuw`S#rv9~ZrEU0A%}y2!USonHqeK7D$6T6*V_bApZbUJ3X2 z)t)RDI?FIKR`BDc?&E>W#Lw%r8w6doL_xH!g#p^hn9xwNwZ)M`}WRAku>iqot zSii0f3wUK`eRh1bTIcnfH$G*H4{!K9dG4(aF9$xCkUy(z*cvy8i@s9qx@A=MCc-^Q zv#LmK*_J6cZ2rjE)x7Bb{D4Qk%JupcL%|=DSqfq{FH^Z~Wo#khPmPl zqN?|xh( z+xsl>q}J-%wTcSti%ermuL=os$abWOZGY6*!Q9xIc^F|4Yk0%BJ&5 zTq{1 z)rad&I-XPdL^C3}+dS9;d%4B+b`(B7cGW^RrBZd0yR5qZJe@u3_@+&7aGCOSuX$D^ zH^+iM+d{d1w%>nabT?)C5g(tET(hU$?N_h>h-mR{>_F5Tv35gGf z`7)Z%RAxN;e$Z3#=9Puc?RO?ByHB#3=_fU-)2K6~N8~QY>CD|REKeM!yslees;km4 zp~v!V+M2i-rfE6HH{W}idb4>(z=ylL%l~GcX4fJ#xU_%F0gy<*tReov~Bou zuhRbikB)ZNTCQu=;B`LWHX}@pDOLHv8O}?tvzLB0x*;WQA$fm){r1a~%G>@#C@Y`e zv?=)3&SxeQR-AhEFk*+_nXj*}XV2l*Uj6-(@C3F+f4;w1pRG9axzCyzUr!4wZI$z> zklAXPWYEJd?v?-Vr17)t!(uXv(~pE~z9_|Szv*?W+Q$?R=i7!Hdn!IE%{=D$S7ox( z1rITIVckhjbpFP=ZvXt|rm?;2WRAPbd}seT!>LrZWYWH>uUYR5m^0V>{`ISd?X+q3 zH5KP37cq_Os>M5tpI=i@yye&yeom3;&=>z}dlL5Z&NX0u^7Qm{yUA)wr);agU5Rm) ze~j$IW`Z|*96eP>(l?N@xC1)fYzpRDd*w&a>``rgyl_WAZrCdUeV ze>+S&m9|x+^7^$p!Hl+svy&E_=@eGy>i%SFTk#S3# zT>S7#VD~T8)~$hDOhpP_h0<3z#NIkG&f6}P;L*W8B{I(Pli3G>lxeMdtE#GA$;~U1 zt=@i*fBxq-m5LLF`~QA=dU{_(oZ8+mrk~b5*Iy*BWWdFg!87CQgsF)_v3!;i604L2 zZ!L1|Hp*7eYOMHlX{mQ#>(&CPjyoUCwdurS%Ma31WNBG4sZc+O?VkASdZ>Ai7bk#B_?%Y+=xC!AwGSE*r?=E2B* z$mPh(vdBm!ehaZbpZR4!efjzFe20x>TgndBwSrGK%k-C6*5=tW%J};5x%|Gl+D%Y^ z5rkIgFcvGAa4+7pJ%CpnEF#cY!Scl6Nb>qwt`00N4lFJUHnBW$2>Etx4OZXb zV8c|T@MvTBS&(T8OiBTfOhpP>)vvD-Sv(Nf^!jn!#T16SxUS_(|vTbi{4`HRgS9PEUPE}Q4U$kkv9|eKn(7yH0+uPf>tt^LHD!?eHq4MGV`T6$k+~+Si iB1Abj{(O>c`^UWALg{F3 Date: Wed, 6 Sep 2017 15:57:26 -0700 Subject: [PATCH 109/248] Remove debug code --- lib/compress/zstd_compress.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 99d5d7963..2364eee25 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -201,33 +201,6 @@ size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) + cctx->outBuffSize + cctx->inBuffSize + ZSTDMT_sizeof_CCtx(cctx->mtctx); } -#if 0 -static void ZSTD_debugPrintCCtxParams(ZSTD_CCtx_params* params) -{ - DEBUGLOG(2, "======CCtxParams======"); - DEBUGLOG(2, "cParams: %u %u %u %u %u %u %u", - params->cParams.windowLog, - params->cParams.chainLog, - params->cParams.hashLog, - params->cParams.searchLog, - params->cParams.searchLength, - params->cParams.targetLength, - params->cParams.strategy); - DEBUGLOG(2, "fParams: %u %u %u", - params->fParams.contentSizeFlag, - params->fParams.checksumFlag, - params->fParams.noDictIDFlag); - DEBUGLOG(2, "cLevel, forceWindow: %u %u", - params->compressionLevel, - params->forceWindow); - DEBUGLOG(2, "ldm: %u %u %u %u %u", - params->ldmParams.enableLdm, - params->ldmParams.hashLog, - params->ldmParams.bucketSizeLog, - params->ldmParams.minMatchLength, - params->ldmParams.hashEveryLog); -} -#endif size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) { From 36374cc3b4f819099baf7b901b227a84a83e179f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 6 Sep 2017 16:15:18 -0700 Subject: [PATCH 110/248] update and clarify lib/README --- lib/README.md | 106 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 43 deletions(-) diff --git a/lib/README.md b/lib/README.md index 79b6fd500..b54bdc91c 100644 --- a/lib/README.md +++ b/lib/README.md @@ -1,57 +1,76 @@ Zstandard library files ================================ -The __lib__ directory contains several directories. -Depending on target use case, it's enough to include only files from relevant directories. +The __lib__ directory is split into several sub-directories, +in order to make it easier to select or exclude specific features. + + +#### Building + +- `make` : generates both static and dynamic libraries +- `make install` : install libraries in default system directories #### API -Zstandard's stable API is exposed within [zstd.h](zstd.h), -at the root of `lib` directory. +Zstandard's stable API is exposed within [lib/zstd.h](zstd.h). #### Advanced API -Some additional API may be useful if you're looking into advanced features : -- common/error_public.h : transforms `size_t` function results into an `enum`, - for precise error handling. -- ZSTD_STATIC_LINKING_ONLY : if you define this macro _before_ including `zstd.h`, - it will give access to advanced and experimental API. +Optional advanced features are exposed via : + +- `lib/common/zstd_errors.h` : translates `size_t` function results + into an `ZSTD_ErrorCode`, for accurate error handling. +- `ZSTD_STATIC_LINKING_ONLY` : if this macro is defined _before_ including `zstd.h`, + it unlocks access to advanced experimental API, + exposed in second part of `zstd.h`. These APIs shall ___never be used with dynamic library___ ! They are not "stable", their definition may change in the future. Only static linking is allowed. -#### ZSTDMT API - -To enable multithreaded compression within the library, invoke `make lib-mt` target. -Prototypes are defined in header file `compress/zstdmt_compress.h`. -When linking a program that uses ZSTDMT API against libzstd.a on a POSIX system, -`-pthread` flag must be provided to the compiler and linker. -Note : ZSTDMT prototypes can still be used with a library built without multithread support, -but in this case, they will be single threaded only. #### Modular build -Directory `common/` is required in all circumstances. -You can select to support compression only, by just adding files from the `compress/` directory, -In a similar way, you can build a decompressor-only library with the `decompress/` directory. - -Other optional functionalities provided are : - -- `dictBuilder/` : source files to create dictionaries. - The API can be consulted in `dictBuilder/zdict.h`. - This module also depends on `common/` and `compress/` . - -- `legacy/` : source code to decompress previous versions of zstd, starting from `v0.1`. - This module also depends on `common/` and `decompress/` . - Library compilation must include directive `ZSTD_LEGACY_SUPPORT = 1` . - The main API can be consulted in `legacy/zstd_legacy.h`. - Advanced API from each version can be found in their relevant header file. - For example, advanced API for version `v0.4` is in `legacy/zstd_v04.h` . +- Directory `lib/common` is always required, for all variants. +- Compression source code lies in `lib/compress` +- Decompression source code lies in `lib/decompress` +- It's possible to include only `compress` or only `decompress`, they don't depend on each other. +- `lib/dictBuilder` : makes it possible to generate dictionaries from a set of samples. + The API is exposed in `lib/dictBuilder/zdict.h`. + This module depends on both `lib/common` and `lib/compress` . +- `lib/legacy` : source code to decompress older zstd formats, starting from `v0.1`. + This module depends on `lib/common` and `lib/decompress`. + To enable this feature, it's necessary to define `ZSTD_LEGACY_SUPPORT = 1` during compilation. + Typically, with `gcc`, add argument `-DZSTD_LEGACY_SUPPORT=1`. + Using higher number limits the number of version supported. + For example, `ZSTD_LEGACY_SUPPORT=2` means : "support legacy formats starting from v0.2+" + The API is exposed in `lib/legacy/zstd_legacy.h`. + Each version also provides a (dedicated) set of advanced API. + For example, advanced API for version `v0.4` is exposed in `lib/legacy/zstd_v04.h` . -#### Using MinGW+MSYS to create DLL +#### Multithreading support + +Multithreading is disabled by default for the library. +Enabling multithreading requires 2 conditions : +- set macro `ZSTD_MULTITHREAD` +- on POSIX systems : compile with pthread (using `-pthread` with `gcc` for example) + +Both conditions are automatically triggered by invoking `make lib-mt` target. +Note that, when linking a POSIX program with a multithreaded version of `libzstd`, +it's necessary to trigger `-pthread` flag during link stage. + +Multithreading capabilities are exposed via : +- private API `lib/compress/zstdmt_compress.h`. + Symbols defined in this header are exposed in library, hence usable. + Note however that this API is planned to be locked and remain strictly internal in the future. +- advanced API `ZSTD_compress_generic()`, defined in `lib/zstd.h`, experimental section. + This API is still considered experimental, but is designed to be labelled "stable" at some point in the future. + It's the recommended entry point to trigger multi-threading. + + +#### Windows : using MinGW+MSYS to create DLL DLL can be created using MinGW+MSYS with the `make libzstd` command. This command creates `dll\libzstd.dll` and the import library `dll\libzstd.lib`. @@ -67,19 +86,20 @@ file it should be linked with `dll\libzstd.dll`. For example: The compiled executable will require ZSTD DLL which is available at `dll\libzstd.dll`. -#### Obsolete streaming API +#### Deprecated API -Streaming is now provided within `zstd.h`. -Older streaming API is still available within `deprecated/zbuff.h`. -It will be removed in a future version. -Consider migrating code towards newer streaming API in `zstd.h`. +Obsolete API on their way out are stored in directory `lib/deprecated`. +At this stage, it contains older streaming prototypes, in `lib/deprecated/zbuff.h`. +Presence in this directory is temporary. +These prototypes will be removed in some future version. +Consider migrating code towards supported streaming API exposed in `zstd.h`. #### Miscellaneous The other files are not source code. There are : - - LICENSE : contains the BSD license text - - Makefile : script to compile or install zstd library (static and dynamic) - - libzstd.pc.in : for pkg-config (`make install`) - - README.md : this file + - `LICENSE` : contains the BSD license text + - `Makefile` : script to build and install zstd library (static and dynamic) + - `libzstd.pc.in` : for `pkg-config` (used in `make install`) + - `README.md` : this file From 1c7b914cdfcc63cf75f40455c4a1593393feb365 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 6 Sep 2017 16:23:39 -0700 Subject: [PATCH 111/248] update README on BUCK file --- lib/README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/README.md b/lib/README.md index b54bdc91c..0c1575d81 100644 --- a/lib/README.md +++ b/lib/README.md @@ -44,7 +44,7 @@ Optional advanced features are exposed via : To enable this feature, it's necessary to define `ZSTD_LEGACY_SUPPORT = 1` during compilation. Typically, with `gcc`, add argument `-DZSTD_LEGACY_SUPPORT=1`. Using higher number limits the number of version supported. - For example, `ZSTD_LEGACY_SUPPORT=2` means : "support legacy formats starting from v0.2+" + For example, `ZSTD_LEGACY_SUPPORT=2` means : "support legacy formats starting from v0.2+". The API is exposed in `lib/legacy/zstd_legacy.h`. Each version also provides a (dedicated) set of advanced API. For example, advanced API for version `v0.4` is exposed in `lib/legacy/zstd_v04.h` . @@ -52,10 +52,10 @@ Optional advanced features are exposed via : #### Multithreading support -Multithreading is disabled by default for the library. +Multithreading is disabled by default when building with `make`. Enabling multithreading requires 2 conditions : - set macro `ZSTD_MULTITHREAD` -- on POSIX systems : compile with pthread (using `-pthread` with `gcc` for example) +- on POSIX systems : compile with pthread (`-pthread` compilation flag for `gcc` for example) Both conditions are automatically triggered by invoking `make lib-mt` target. Note that, when linking a POSIX program with a multithreaded version of `libzstd`, @@ -63,11 +63,11 @@ it's necessary to trigger `-pthread` flag during link stage. Multithreading capabilities are exposed via : - private API `lib/compress/zstdmt_compress.h`. - Symbols defined in this header are exposed in library, hence usable. + Symbols defined in this header are currently exposed in `libzstd`, hence usable. Note however that this API is planned to be locked and remain strictly internal in the future. - advanced API `ZSTD_compress_generic()`, defined in `lib/zstd.h`, experimental section. This API is still considered experimental, but is designed to be labelled "stable" at some point in the future. - It's the recommended entry point to trigger multi-threading. + It's the recommended entry point for multi-threading operations. #### Windows : using MinGW+MSYS to create DLL @@ -100,6 +100,7 @@ Consider migrating code towards supported streaming API exposed in `zstd.h`. The other files are not source code. There are : - `LICENSE` : contains the BSD license text - - `Makefile` : script to build and install zstd library (static and dynamic) + - `Makefile` : `make` script to build and install zstd library (static and dynamic) + - `BUCK` : support for `buck` build system (https://buckbuild.com/) - `libzstd.pc.in` : for `pkg-config` (used in `make install`) - `README.md` : this file From 3a12531a3dd1a4e2d62904f163a94d54dd45a264 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 6 Sep 2017 16:35:49 -0700 Subject: [PATCH 112/248] lib/Makefile : better support for GNU conventions see https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html --- lib/Makefile | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index b12fd6135..6de1450b3 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -113,16 +113,17 @@ clean: #----------------------------------------------------------------------------- ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS)) -ifneq (,$(filter $(shell uname),SunOS)) -INSTALL ?= ginstall -else -INSTALL ?= install -endif - -PREFIX ?= /usr/local -DESTDIR ?= -LIBDIR ?= $(PREFIX)/lib -INCLUDEDIR ?= $(PREFIX)/include +DESTDIR ?= +# directory variables : GNU conventions prefer lowercase +# see https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html +# support both lower and uppercase (BSD), use uppercase in script +prefix ?= /usr/local +PREFIX ?= $(prefix) +exec_prefix ?= $(PREFIX) +libdir ?= $(exec_prefix)/lib +LIBDIR ?= $(libdir) +includedir ?= $(PREFIX)/include +INCLUDEDIR ?= $(includedir) ifneq (,$(filter $(shell uname),OpenBSD FreeBSD NetBSD DragonFly)) PKGCONFIGDIR ?= $(PREFIX)/libdata/pkgconfig @@ -130,8 +131,14 @@ else PKGCONFIGDIR ?= $(LIBDIR)/pkgconfig endif -INSTALL_LIB ?= $(INSTALL) -m 755 -INSTALL_DATA ?= $(INSTALL) -m 644 +ifneq (,$(filter $(shell uname),SunOS)) +INSTALL ?= ginstall +else +INSTALL ?= install +endif + +INSTALL_PROGRAM ?= $(INSTALL) +INSTALL_DATA ?= $(INSTALL) -m 644 libzstd.pc: @@ -148,9 +155,9 @@ install: libzstd.a libzstd libzstd.pc @$(INSTALL_DATA) libzstd.pc $(DESTDIR)$(PKGCONFIGDIR)/ @echo Installing libraries @$(INSTALL_DATA) libzstd.a $(DESTDIR)$(LIBDIR) - @$(INSTALL_LIB) libzstd.$(SHARED_EXT_VER) $(DESTDIR)$(LIBDIR) - @ln -sf libzstd.$(SHARED_EXT_VER) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR) - @ln -sf libzstd.$(SHARED_EXT_VER) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT) + @$(INSTALL_PROGRAM) $(LIBZSTD) $(DESTDIR)$(LIBDIR) + @ln -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR) + @ln -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT) @echo Installing includes @$(INSTALL_DATA) zstd.h $(DESTDIR)$(INCLUDEDIR) @$(INSTALL_DATA) common/zstd_errors.h $(DESTDIR)$(INCLUDEDIR) @@ -162,7 +169,7 @@ uninstall: @$(RM) $(DESTDIR)$(LIBDIR)/libzstd.a @$(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT) @$(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR) - @$(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_VER) + @$(RM) $(DESTDIR)$(LIBDIR)/$(LIBZSTD) @$(RM) $(DESTDIR)$(PKGCONFIGDIR)/libzstd.pc @$(RM) $(DESTDIR)$(INCLUDEDIR)/zstd.h @$(RM) $(DESTDIR)$(INCLUDEDIR)/zstd_errors.h From baa37c33624971852739ab6c9378b5a9f0907bef Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 6 Sep 2017 16:53:59 -0700 Subject: [PATCH 113/248] programs/Makefile : better support for GNU conventions see https://www.gnu.org/prep/standards/html_node/Command-Variables.html --- lib/README.md | 2 ++ programs/Makefile | 38 ++++++++++++++++++++++++-------------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/lib/README.md b/lib/README.md index 0c1575d81..df136c486 100644 --- a/lib/README.md +++ b/lib/README.md @@ -7,6 +7,8 @@ in order to make it easier to select or exclude specific features. #### Building +`Makefile` script is provided, supporting the standard set of commands, +directories, and variables (see https://www.gnu.org/prep/standards/html_node/Command-Variables.html). - `make` : generates both static and dynamic libraries - `make install` : install libraries in default system directories diff --git a/programs/Makefile b/programs/Makefile index 5a7c373bf..b13629df9 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -209,8 +209,8 @@ zstd-decompress: $(ZSTDCOMMON_FILES) $(ZSTDDECOMP_FILES) zstdcli.c fileio.c zstd-compress: $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES) zstdcli.c fileio.c $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT -DZSTD_NODECOMPRESS $^ -o $@$(EXT) -# zstd is now built with multithreading enabled y default zstdmt: zstd + ln -sf zstd zstdmt .PHONY: generate_res generate_res: @@ -252,25 +252,35 @@ ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD Ne list: @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs +DESTDIR ?= +# directory variables : GNU conventions prefer lowercase +# see https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html +# support both lower and uppercase (BSD), use uppercase in script +prefix ?= /usr/local +PREFIX ?= $(prefix) +exec_prefix ?= $(PREFIX) +bindir ?= $(exec_prefix)/bin +BINDIR ?= $(bindir) +datarootdir ?= $(PREFIX)/share +mandir ?= $(datarootdir)/man +man1dir ?= $(mandir)/man1 + +ifneq (,$(filter $(shell uname),OpenBSD FreeBSD NetBSD DragonFly SunOS)) +MANDIR ?= $(PREFIX)/man/man1 +else +MANDIR ?= $(man1dir) +endif + ifneq (,$(filter $(shell uname),SunOS)) INSTALL ?= ginstall else INSTALL ?= install endif -PREFIX ?= /usr/local -DESTDIR ?= -BINDIR ?= $(PREFIX)/bin - -ifneq (,$(filter $(shell uname),OpenBSD FreeBSD NetBSD DragonFly SunOS)) -MANDIR ?= $(PREFIX)/man/man1 -else -MANDIR ?= $(PREFIX)/share/man/man1 -endif - -INSTALL_PROGRAM ?= $(INSTALL) -m 755 -INSTALL_SCRIPT ?= $(INSTALL) -m 755 -INSTALL_MAN ?= $(INSTALL) -m 644 +INSTALL_PROGRAM ?= $(INSTALL) +INSTALL_SCRIPT ?= $(INSTALL_PROGRAM) +INSTALL_DATA ?= $(INSTALL) -m 644 +INSTALL_MAN ?= $(INSTALL_DATA) .PHONY: install install: zstd From 360428c5d94d97bf481227c70eedcf7ddd9a0576 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Wed, 6 Sep 2017 17:56:01 -0700 Subject: [PATCH 114/248] Move ldm functions to their own file --- build/VS2008/fullbench/fullbench.vcproj | 8 + build/VS2008/fuzzer/fuzzer.vcproj | 8 + build/VS2008/zstd/zstd.vcproj | 8 + build/VS2008/zstdlib/zstdlib.vcproj | 8 + build/VS2010/fullbench/fullbench.vcxproj | 2 + build/VS2010/fuzzer/fuzzer.vcxproj | 2 + build/VS2010/libzstd-dll/libzstd-dll.vcxproj | 2 + build/VS2010/libzstd/libzstd.vcxproj | 2 + build/VS2010/zstd/zstd.vcxproj | 2 + build/cmake/lib/CMakeLists.txt | 2 + lib/compress/zstd_compress.c | 745 +------------------ lib/compress/zstd_ldm.c | 702 +++++++++++++++++ lib/compress/zstd_ldm.h | 67 ++ 13 files changed, 820 insertions(+), 738 deletions(-) create mode 100644 lib/compress/zstd_ldm.c create mode 100644 lib/compress/zstd_ldm.h diff --git a/build/VS2008/fullbench/fullbench.vcproj b/build/VS2008/fullbench/fullbench.vcproj index 05ec5ca06..715ea2579 100644 --- a/build/VS2008/fullbench/fullbench.vcproj +++ b/build/VS2008/fullbench/fullbench.vcproj @@ -403,6 +403,10 @@ + + + + diff --git a/build/VS2008/fuzzer/fuzzer.vcproj b/build/VS2008/fuzzer/fuzzer.vcproj index 700dd7ebd..1421619a1 100644 --- a/build/VS2008/fuzzer/fuzzer.vcproj +++ b/build/VS2008/fuzzer/fuzzer.vcproj @@ -415,6 +415,10 @@ + + + + diff --git a/build/VS2008/zstd/zstd.vcproj b/build/VS2008/zstd/zstd.vcproj index 86dd3a254..dbd211c06 100644 --- a/build/VS2008/zstd/zstd.vcproj +++ b/build/VS2008/zstd/zstd.vcproj @@ -459,6 +459,10 @@ + + + + diff --git a/build/VS2008/zstdlib/zstdlib.vcproj b/build/VS2008/zstdlib/zstdlib.vcproj index ac8f896c3..340a4cd89 100644 --- a/build/VS2008/zstdlib/zstdlib.vcproj +++ b/build/VS2008/zstdlib/zstdlib.vcproj @@ -403,6 +403,10 @@ + + + + + @@ -189,6 +190,7 @@ + diff --git a/build/VS2010/fuzzer/fuzzer.vcxproj b/build/VS2010/fuzzer/fuzzer.vcxproj index 9f00899da..6fe327209 100644 --- a/build/VS2010/fuzzer/fuzzer.vcxproj +++ b/build/VS2010/fuzzer/fuzzer.vcxproj @@ -169,6 +169,7 @@ + @@ -192,6 +193,7 @@ + diff --git a/build/VS2010/libzstd-dll/libzstd-dll.vcxproj b/build/VS2010/libzstd-dll/libzstd-dll.vcxproj index 0a4be69df..2d04c6935 100644 --- a/build/VS2010/libzstd-dll/libzstd-dll.vcxproj +++ b/build/VS2010/libzstd-dll/libzstd-dll.vcxproj @@ -33,6 +33,7 @@ + @@ -76,6 +77,7 @@ + diff --git a/build/VS2010/libzstd/libzstd.vcxproj b/build/VS2010/libzstd/libzstd.vcxproj index 51b840677..c01a5d179 100644 --- a/build/VS2010/libzstd/libzstd.vcxproj +++ b/build/VS2010/libzstd/libzstd.vcxproj @@ -33,6 +33,7 @@ + @@ -76,6 +77,7 @@ + diff --git a/build/VS2010/zstd/zstd.vcxproj b/build/VS2010/zstd/zstd.vcxproj index 90470180d..ace343465 100644 --- a/build/VS2010/zstd/zstd.vcxproj +++ b/build/VS2010/zstd/zstd.vcxproj @@ -34,6 +34,7 @@ + @@ -69,6 +70,7 @@ + diff --git a/build/cmake/lib/CMakeLists.txt b/build/cmake/lib/CMakeLists.txt index f4b7e3753..f5d2eff92 100644 --- a/build/cmake/lib/CMakeLists.txt +++ b/build/cmake/lib/CMakeLists.txt @@ -42,6 +42,7 @@ SET(Sources ${LIBRARY_DIR}/compress/zstd_double_fast.c ${LIBRARY_DIR}/compress/zstd_lazy.c ${LIBRARY_DIR}/compress/zstd_opt.c + ${LIBRARY_DIR}/compress/zstd_ldm.c ${LIBRARY_DIR}/decompress/huf_decompress.c ${LIBRARY_DIR}/decompress/zstd_decompress.c ${LIBRARY_DIR}/dictBuilder/cover.c @@ -67,6 +68,7 @@ SET(Headers ${LIBRARY_DIR}/compress/zstd_double_fast.h ${LIBRARY_DIR}/compress/zstd_lazy.h ${LIBRARY_DIR}/compress/zstd_opt.h + ${LIBRARY_DIR}/compress/zstd_ldm.h ${LIBRARY_DIR}/compress/zstdmt_compress.h ${LIBRARY_DIR}/dictBuilder/zdict.h ${LIBRARY_DIR}/deprecated/zbuff.h) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 3abc1e913..5ea00b8e2 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -30,14 +30,7 @@ #include "zstd_double_fast.h" #include "zstd_lazy.h" #include "zstd_opt.h" - - -#define LDM_BUCKET_SIZE_LOG 3 -#define LDM_MIN_MATCH_LENGTH 64 -#define LDM_WINDOW_LOG 27 -#define LDM_HASH_LOG 20 -#define LDM_HASH_CHAR_OFFSET 10 -#define LDM_HASHEVERYLOG_NOTSET 9999 +#include "zstd_ldm.h" /*-************************************* @@ -135,33 +128,6 @@ size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) + cctx->outBuffSize + cctx->inBuffSize + ZSTDMT_sizeof_CCtx(cctx->mtctx); } -#if 0 -static void ZSTD_debugPrintCCtxParams(ZSTD_CCtx_params* params) -{ - DEBUGLOG(2, "======CCtxParams======"); - DEBUGLOG(2, "cParams: %u %u %u %u %u %u %u", - params->cParams.windowLog, - params->cParams.chainLog, - params->cParams.hashLog, - params->cParams.searchLog, - params->cParams.searchLength, - params->cParams.targetLength, - params->cParams.strategy); - DEBUGLOG(2, "fParams: %u %u %u", - params->fParams.contentSizeFlag, - params->fParams.checksumFlag, - params->fParams.noDictIDFlag); - DEBUGLOG(2, "cLevel, forceWindow: %u %u", - params->compressionLevel, - params->forceWindow); - DEBUGLOG(2, "ldm: %u %u %u %u %u", - params->ldmParams.enableLdm, - params->ldmParams.hashLog, - params->ldmParams.bucketSizeLog, - params->ldmParams.minMatchLength, - params->ldmParams.hashEveryLog); -} -#endif size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) { @@ -274,17 +240,6 @@ size_t ZSTDMT_CCtxParam_setMTCtxParameter( ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value); size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads); -static size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm) -{ - ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX); - params->enableLdm = enableLdm>0; - params->hashLog = LDM_HASH_LOG; - params->bucketSizeLog = LDM_BUCKET_SIZE_LOG; - params->minMatchLength = LDM_MIN_MATCH_LENGTH; - params->hashEveryLog = LDM_HASHEVERYLOG_NOTSET; - return 0; -} - size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value) { if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); @@ -454,7 +409,7 @@ size_t ZSTD_CCtxParam_setParameter( case ZSTD_p_enableLongDistanceMatching : if (value != 0) { ZSTD_cLevelToCCtxParams(params); - params->cParams.windowLog = LDM_WINDOW_LOG; + params->cParams.windowLog = ZSTD_LDM_WINDOW_LOG; } return ZSTD_ldm_initializeParameters(¶ms->ldmParams, value); @@ -689,15 +644,6 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); } -/* Estimate the space needed for long distance matching tables. */ -static size_t ZSTD_ldm_getTableSize(U32 hashLog, U32 bucketSizeLog) { - size_t const ldmHSize = ((size_t)1) << hashLog; - size_t const ldmBucketSizeLog = MIN(bucketSizeLog, hashLog); - size_t const ldmBucketSize = - ((size_t)1) << (hashLog - ldmBucketSizeLog); - return ldmBucketSize + (ldmHSize * (sizeof(ldmEntry_t))); -} - size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params) { /* Estimate CCtx size is supported for single-threaded compression only. */ @@ -832,8 +778,6 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pl typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e; typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e; -static U64 ZSTD_ldm_getHashPower(U32 minMatchLength); - /*! ZSTD_resetCCtx_internal() : note : `params` are assumed fully validated at this stage */ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, @@ -847,7 +791,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, if (ZSTD_equivalentParams(params, zc->appliedParams)) { DEBUGLOG(5, "ZSTD_equivalentParams()==1"); assert(!(params.ldmParams.enableLdm && - params.ldmParams.hashEveryLog == LDM_HASHEVERYLOG_NOTSET)); + params.ldmParams.hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET)); zc->entropy->hufCTable_repeatMode = HUF_repeat_none; zc->entropy->offcode_repeatMode = FSE_repeat_none; zc->entropy->matchlength_repeatMode = FSE_repeat_none; @@ -857,13 +801,8 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, if (params.ldmParams.enableLdm) { /* Adjust long distance matching parameters */ - if (params.ldmParams.hashEveryLog == LDM_HASHEVERYLOG_NOTSET) { - params.ldmParams.hashEveryLog = - params.cParams.windowLog < params.ldmParams.hashLog ? - 0 : params.cParams.windowLog - params.ldmParams.hashLog; - } - params.ldmParams.bucketSizeLog = - MIN(params.ldmParams.bucketSizeLog, params.ldmParams.hashLog); + ZSTD_ldm_adjustParameters(¶ms.ldmParams, params.cParams.windowLog); + assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); zc->ldmState.hashPower = ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength); } @@ -994,7 +933,6 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, size_t const ldmBucketSize = ((size_t)1) << (params.ldmParams.hashLog - params.ldmParams.bucketSizeLog); - assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); memset(ptr, 0, ldmBucketSize); zc->ldmState.bucketOffsets = (BYTE*)ptr; ptr = zc->ldmState.bucketOffsets + ldmBucketSize; @@ -1553,9 +1491,10 @@ MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr, } /* ZSTD_selectBlockCompressor() : + * Not static, but internal use only (used by long distance matcher) * assumption : strat is a valid strategy */ typedef size_t (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize); -static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict) +ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict) { static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = { { ZSTD_compressBlock_fast /* default for 0 */, @@ -1574,676 +1513,6 @@ static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int return blockCompressor[extDict!=0][(U32)strat]; } -/*-************************************* -* Long distance matching -***************************************/ - -/** ZSTD_ldm_getSmallHash() : - * numBits should be <= 32 - * If numBits==0, returns 0. - * @return : the most significant numBits of value. */ -static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits) -{ - assert(numBits <= 32); - return numBits == 0 ? 0 : (U32)(value >> (64 - numBits)); -} - -/** ZSTD_ldm_getChecksum() : - * numBitsToDiscard should be <= 32 - * @return : the next most significant 32 bits after numBitsToDiscard */ -static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard) -{ - assert(numBitsToDiscard <= 32); - return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF; -} - -/** ZSTD_ldm_getTag() ; - * Given the hash, returns the most significant numTagBits bits - * after (32 + hbits) bits. - * - * If there are not enough bits remaining, return the last - * numTagBits bits. */ -static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits) -{ - assert(numTagBits <= 32 && hbits <= 32); - if (32 - hbits < numTagBits) { - return hash & ((1 << numTagBits) - 1); - } else { - return (hash >> (32 - hbits - numTagBits)) & ((1 << numTagBits) - 1); - } -} - -/** ZSTD_ldm_getBucket() : - * Returns a pointer to the start of the bucket associated with hash. */ -static ldmEntry_t* ZSTD_ldm_getBucket( - ldmState_t* ldmState, size_t hash, ldmParams_t const ldmParams) -{ - return ldmState->hashTable + (hash << ldmParams.bucketSizeLog); -} - -/** ZSTD_ldm_insertEntry() : - * Insert the entry with corresponding hash into the hash table */ -static void ZSTD_ldm_insertEntry(ldmState_t* ldmState, - size_t const hash, const ldmEntry_t entry, - ldmParams_t const ldmParams) -{ - BYTE* const bucketOffsets = ldmState->bucketOffsets; - *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry; - bucketOffsets[hash]++; - bucketOffsets[hash] &= (1 << ldmParams.bucketSizeLog) - 1; -} - -/** ZSTD_ldm_makeEntryAndInsertByTag() : - * - * Gets the small hash, checksum, and tag from the rollingHash. - * - * If the tag matches (1 << ldmParams.hashEveryLog)-1, then - * creates an ldmEntry from the offset, and inserts it into the hash table. - * - * hBits is the length of the small hash, which is the most significant hBits - * of rollingHash. The checksum is the next 32 most significant bits, followed - * by ldmParams.hashEveryLog bits that make up the tag. */ -static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState, - U64 const rollingHash, - U32 const hBits, - U32 const offset, - ldmParams_t const ldmParams) -{ - U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog); - U32 const tagMask = (1 << ldmParams.hashEveryLog) - 1; - if (tag == tagMask) { - U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits); - U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); - ldmEntry_t entry; - entry.offset = offset; - entry.checksum = checksum; - ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams); - } -} - -/** ZSTD_ldm_getRollingHash() : - * Get a 64-bit hash using the first len bytes from buf. - * - * Giving bytes s = s_1, s_2, ... s_k, the hash is defined to be - * H(s) = s_1*(a^(k-1)) + s_2*(a^(k-2)) + ... + s_k*(a^0) - * - * where the constant a is defined to be prime8bytes. - * - * The implementation adds an offset to each byte, so - * H(s) = (s_1 + HASH_CHAR_OFFSET)*(a^(k-1)) + ... */ -static U64 ZSTD_ldm_getRollingHash(const BYTE* buf, U32 len) -{ - U64 ret = 0; - U32 i; - for (i = 0; i < len; i++) { - ret *= prime8bytes; - ret += buf[i] + LDM_HASH_CHAR_OFFSET; - } - return ret; -} - -/** ZSTD_ldm_ipow() : - * Return base^exp. */ -static U64 ZSTD_ldm_ipow(U64 base, U64 exp) -{ - U64 ret = 1; - while (exp) { - if (exp & 1) { ret *= base; } - exp >>= 1; - base *= base; - } - return ret; -} - -static U64 ZSTD_ldm_getHashPower(U32 minMatchLength) { - assert(minMatchLength >= ZSTD_LDM_MINMATCH_MIN); - return ZSTD_ldm_ipow(prime8bytes, minMatchLength - 1); -} - -/** ZSTD_ldm_updateHash() : - * Updates hash by removing toRemove and adding toAdd. */ -static U64 ZSTD_ldm_updateHash(U64 hash, BYTE toRemove, BYTE toAdd, U64 hashPower) -{ - hash -= ((toRemove + LDM_HASH_CHAR_OFFSET) * hashPower); - hash *= prime8bytes; - hash += toAdd + LDM_HASH_CHAR_OFFSET; - return hash; -} - -/** ZSTD_ldm_countBackwardsMatch() : - * Returns the number of bytes that match backwards before pIn and pMatch. - * - * We count only bytes where pMatch >= pBase and pIn >= pAnchor. */ -static size_t ZSTD_ldm_countBackwardsMatch( - const BYTE* pIn, const BYTE* pAnchor, - const BYTE* pMatch, const BYTE* pBase) -{ - size_t matchLength = 0; - while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) { - pIn--; - pMatch--; - matchLength++; - } - return matchLength; -} - -/** ZSTD_ldm_fillFastTables() : - * - * Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies. - * This is similar to ZSTD_loadDictionaryContent. - * - * The tables for the other strategies are filled within their - * block compressors. */ -static size_t ZSTD_ldm_fillFastTables(ZSTD_CCtx* zc, const void* end) -{ - const BYTE* const iend = (const BYTE*)end; - const U32 mls = zc->appliedParams.cParams.searchLength; - - switch(zc->appliedParams.cParams.strategy) - { - case ZSTD_fast: - ZSTD_fillHashTable(zc, iend, mls); - zc->nextToUpdate = (U32)(iend - zc->base); - break; - - case ZSTD_dfast: - ZSTD_fillDoubleHashTable(zc, iend, mls); - zc->nextToUpdate = (U32)(iend - zc->base); - break; - - case ZSTD_greedy: - case ZSTD_lazy: - case ZSTD_lazy2: - case ZSTD_btlazy2: - case ZSTD_btopt: - case ZSTD_btultra: - break; - default: - assert(0); /* not possible : not a valid strategy id */ - } - - return 0; -} - -/** ZSTD_ldm_fillLdmHashTable() : - * - * Fills hashTable from (lastHashed + 1) to iend (non-inclusive). - * lastHash is the rolling hash that corresponds to lastHashed. - * - * Returns the rolling hash corresponding to position iend-1. */ -static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state, - U64 lastHash, const BYTE* lastHashed, - const BYTE* iend, const BYTE* base, - U32 hBits, ldmParams_t const ldmParams) -{ - U64 rollingHash = lastHash; - const BYTE* cur = lastHashed + 1; - - while (cur < iend) { - rollingHash = ZSTD_ldm_updateHash(rollingHash, cur[-1], - cur[ldmParams.minMatchLength-1], - state->hashPower); - ZSTD_ldm_makeEntryAndInsertByTag(state, - rollingHash, hBits, - (U32)(cur - base), ldmParams); - ++cur; - } - return rollingHash; -} - - -/** ZSTD_ldm_limitTableUpdate() : - * - * Sets cctx->nextToUpdate to a position corresponding closer to anchor - * if it is far way - * (after a long match, only update tables a limited amount). */ -static void ZSTD_ldm_limitTableUpdate(ZSTD_CCtx* cctx, const BYTE* anchor) -{ - U32 const current = (U32)(anchor - cctx->base); - if (current > cctx->nextToUpdate + 1024) { - cctx->nextToUpdate = - current - MIN(512, current - cctx->nextToUpdate - 1024); - } -} - -/** ZSTD_compressBlock_ldm_generic() : - * - * This is a block compressor intended for long distance matching. - * - * The function searches for matches of length at least - * ldmParams.minMatchLength using a hash table in cctx->ldmState. - * Matches can be at a distance of up to cParams.windowLog. - * - * Upon finding a match, the unmatched literals are compressed using a - * ZSTD_blockCompressor (depending on the strategy in the compression - * parameters), which stores the matched sequences. The "long distance" - * match is then stored with the remaining literals from the - * ZSTD_blockCompressor. */ -FORCE_INLINE_TEMPLATE -size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx, - const void* src, size_t srcSize) -{ - ldmState_t* const ldmState = &(cctx->ldmState); - const ldmParams_t ldmParams = cctx->appliedParams.ldmParams; - const U64 hashPower = ldmState->hashPower; - const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog; - const U32 ldmBucketSize = (1 << ldmParams.bucketSizeLog); - const U32 ldmTagMask = (1 << ldmParams.hashEveryLog) - 1; - seqStore_t* const seqStorePtr = &(cctx->seqStore); - const BYTE* const base = cctx->base; - const BYTE* const istart = (const BYTE*)src; - const BYTE* ip = istart; - const BYTE* anchor = istart; - const U32 lowestIndex = cctx->dictLimit; - const BYTE* const lowest = base + lowestIndex; - const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = iend - ldmParams.minMatchLength; - - const ZSTD_blockCompressor blockCompressor = - ZSTD_selectBlockCompressor(cctx->appliedParams.cParams.strategy, 0); - U32* const repToConfirm = seqStorePtr->repToConfirm; - U32 savedRep[ZSTD_REP_NUM]; - U64 rollingHash = 0; - const BYTE* lastHashed = NULL; - size_t i, lastLiterals; - - /* Save seqStorePtr->rep and copy repToConfirm */ - for (i = 0; i < ZSTD_REP_NUM; i++) - savedRep[i] = repToConfirm[i] = seqStorePtr->rep[i]; - - /* Main Search Loop */ - while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ - size_t mLength; - U32 const current = (U32)(ip - base); - size_t forwardMatchLength = 0, backwardMatchLength = 0; - ldmEntry_t* bestEntry = NULL; - if (ip != istart) { - rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0], - lastHashed[ldmParams.minMatchLength], - hashPower); - } else { - rollingHash = ZSTD_ldm_getRollingHash(ip, ldmParams.minMatchLength); - } - lastHashed = ip; - - /* Do not insert and do not look for a match */ - if (ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog) != - ldmTagMask) { - ip++; - continue; - } - - /* Get the best entry and compute the match lengths */ - { - ldmEntry_t* const bucket = - ZSTD_ldm_getBucket(ldmState, - ZSTD_ldm_getSmallHash(rollingHash, hBits), - ldmParams); - ldmEntry_t* cur; - size_t bestMatchLength = 0; - U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); - - for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) { - const BYTE* const pMatch = cur->offset + base; - size_t curForwardMatchLength, curBackwardMatchLength, - curTotalMatchLength; - if (cur->checksum != checksum || cur->offset <= lowestIndex) { - continue; - } - - curForwardMatchLength = ZSTD_count(ip, pMatch, iend); - if (curForwardMatchLength < ldmParams.minMatchLength) { - continue; - } - curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch( - ip, anchor, pMatch, lowest); - curTotalMatchLength = curForwardMatchLength + - curBackwardMatchLength; - - if (curTotalMatchLength > bestMatchLength) { - bestMatchLength = curTotalMatchLength; - forwardMatchLength = curForwardMatchLength; - backwardMatchLength = curBackwardMatchLength; - bestEntry = cur; - } - } - } - - /* No match found -- continue searching */ - if (bestEntry == NULL) { - ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, - hBits, current, - ldmParams); - ip++; - continue; - } - - /* Match found */ - mLength = forwardMatchLength + backwardMatchLength; - ip -= backwardMatchLength; - - /* Call the block compressor on the remaining literals */ - { - U32 const matchIndex = bestEntry->offset; - const BYTE* const match = base + matchIndex - backwardMatchLength; - U32 const offset = (U32)(ip - match); - - /* Overwrite rep codes */ - for (i = 0; i < ZSTD_REP_NUM; i++) - seqStorePtr->rep[i] = repToConfirm[i]; - - /* Fill tables for block compressor */ - ZSTD_ldm_limitTableUpdate(cctx, anchor); - ZSTD_ldm_fillFastTables(cctx, anchor); - - /* Call block compressor and get remaining literals */ - lastLiterals = blockCompressor(cctx, anchor, ip - anchor); - cctx->nextToUpdate = (U32)(ip - base); - - /* Update repToConfirm with the new offset */ - for (i = ZSTD_REP_NUM - 1; i > 0; i--) - repToConfirm[i] = repToConfirm[i-1]; - repToConfirm[0] = offset; - - /* Store the sequence with the leftover literals */ - ZSTD_storeSeq(seqStorePtr, lastLiterals, ip - lastLiterals, - offset + ZSTD_REP_MOVE, mLength - MINMATCH); - } - - /* Insert the current entry into the hash table */ - ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, - (U32)(lastHashed - base), - ldmParams); - - assert(ip + backwardMatchLength == lastHashed); - - /* Fill the hash table from lastHashed+1 to ip+mLength*/ - /* Heuristic: don't need to fill the entire table at end of block */ - if (ip + mLength < ilimit) { - rollingHash = ZSTD_ldm_fillLdmHashTable( - ldmState, rollingHash, lastHashed, - ip + mLength, base, hBits, ldmParams); - lastHashed = ip + mLength - 1; - } - ip += mLength; - anchor = ip; - /* Check immediate repcode */ - while ( (ip < ilimit) - && ( (repToConfirm[1] > 0) && (repToConfirm[1] <= (U32)(ip-lowest)) - && (MEM_read32(ip) == MEM_read32(ip - repToConfirm[1])) )) { - - size_t const rLength = ZSTD_count(ip+4, ip+4-repToConfirm[1], - iend) + 4; - /* Swap repToConfirm[1] <=> repToConfirm[0] */ - { - U32 const tmpOff = repToConfirm[1]; - repToConfirm[1] = repToConfirm[0]; - repToConfirm[0] = tmpOff; - } - - ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH); - - /* Fill the hash table from lastHashed+1 to ip+rLength*/ - if (ip + rLength < ilimit) { - rollingHash = ZSTD_ldm_fillLdmHashTable( - ldmState, rollingHash, lastHashed, - ip + rLength, base, hBits, ldmParams); - lastHashed = ip + rLength - 1; - } - ip += rLength; - anchor = ip; - } - } - - /* Overwrite rep */ - for (i = 0; i < ZSTD_REP_NUM; i++) - seqStorePtr->rep[i] = repToConfirm[i]; - - ZSTD_ldm_limitTableUpdate(cctx, anchor); - ZSTD_ldm_fillFastTables(cctx, anchor); - - lastLiterals = blockCompressor(cctx, anchor, iend - anchor); - cctx->nextToUpdate = (U32)(iend - base); - - /* Restore seqStorePtr->rep */ - for (i = 0; i < ZSTD_REP_NUM; i++) - seqStorePtr->rep[i] = savedRep[i]; - - /* Return the last literals size */ - return lastLiterals; -} - -static size_t ZSTD_compressBlock_ldm(ZSTD_CCtx* ctx, - const void* src, size_t srcSize) -{ - return ZSTD_compressBlock_ldm_generic(ctx, src, srcSize); -} - -static size_t ZSTD_compressBlock_ldm_extDict_generic( - ZSTD_CCtx* ctx, - const void* src, size_t srcSize) -{ - ldmState_t* const ldmState = &(ctx->ldmState); - const ldmParams_t ldmParams = ctx->appliedParams.ldmParams; - const U64 hashPower = ldmState->hashPower; - const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog; - const U32 ldmBucketSize = (1 << ldmParams.bucketSizeLog); - const U32 ldmTagMask = (1 << ldmParams.hashEveryLog) - 1; - seqStore_t* const seqStorePtr = &(ctx->seqStore); - const BYTE* const base = ctx->base; - const BYTE* const dictBase = ctx->dictBase; - const BYTE* const istart = (const BYTE*)src; - const BYTE* ip = istart; - const BYTE* anchor = istart; - const U32 lowestIndex = ctx->lowLimit; - const BYTE* const dictStart = dictBase + lowestIndex; - const U32 dictLimit = ctx->dictLimit; - const BYTE* const lowPrefixPtr = base + dictLimit; - const BYTE* const dictEnd = dictBase + dictLimit; - const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = iend - ldmParams.minMatchLength; - - const ZSTD_blockCompressor blockCompressor = - ZSTD_selectBlockCompressor(ctx->appliedParams.cParams.strategy, 1); - U32* const repToConfirm = seqStorePtr->repToConfirm; - U32 savedRep[ZSTD_REP_NUM]; - U64 rollingHash = 0; - const BYTE* lastHashed = NULL; - size_t i, lastLiterals; - - /* Save seqStorePtr->rep and copy repToConfirm */ - for (i = 0; i < ZSTD_REP_NUM; i++) { - savedRep[i] = repToConfirm[i] = seqStorePtr->rep[i]; - } - - /* Search Loop */ - while (ip < ilimit) { /* < instead of <=, because (ip+1) */ - size_t mLength; - const U32 current = (U32)(ip-base); - size_t forwardMatchLength = 0, backwardMatchLength = 0; - ldmEntry_t* bestEntry = NULL; - if (ip != istart) { - rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0], - lastHashed[ldmParams.minMatchLength], - hashPower); - } else { - rollingHash = ZSTD_ldm_getRollingHash(ip, ldmParams.minMatchLength); - } - lastHashed = ip; - - if (ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog) != - ldmTagMask) { - /* Don't insert and don't look for a match */ - ip++; - continue; - } - - /* Get the best entry and compute the match lengths */ - { - ldmEntry_t* const bucket = - ZSTD_ldm_getBucket(ldmState, - ZSTD_ldm_getSmallHash(rollingHash, hBits), - ldmParams); - ldmEntry_t* cur; - size_t bestMatchLength = 0; - U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); - - for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) { - const BYTE* const curMatchBase = - cur->offset < dictLimit ? dictBase : base; - const BYTE* const pMatch = curMatchBase + cur->offset; - const BYTE* const matchEnd = - cur->offset < dictLimit ? dictEnd : iend; - const BYTE* const lowMatchPtr = - cur->offset < dictLimit ? dictStart : lowPrefixPtr; - size_t curForwardMatchLength, curBackwardMatchLength, - curTotalMatchLength; - - if (cur->checksum != checksum || cur->offset <= lowestIndex) { - continue; - } - - curForwardMatchLength = ZSTD_count_2segments( - ip, pMatch, iend, - matchEnd, lowPrefixPtr); - if (curForwardMatchLength < ldmParams.minMatchLength) { - continue; - } - curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch( - ip, anchor, pMatch, lowMatchPtr); - curTotalMatchLength = curForwardMatchLength + - curBackwardMatchLength; - - if (curTotalMatchLength > bestMatchLength) { - bestMatchLength = curTotalMatchLength; - forwardMatchLength = curForwardMatchLength; - backwardMatchLength = curBackwardMatchLength; - bestEntry = cur; - } - } - } - - /* No match found -- continue searching */ - if (bestEntry == NULL) { - ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, - (U32)(lastHashed - base), - ldmParams); - ip++; - continue; - } - - /* Match found */ - mLength = forwardMatchLength + backwardMatchLength; - ip -= backwardMatchLength; - - /* Call the block compressor on the remaining literals */ - { - /* ip = current - backwardMatchLength - * The match is at (bestEntry->offset - backwardMatchLength) */ - U32 const matchIndex = bestEntry->offset; - U32 const offset = current - matchIndex; - - /* Overwrite rep codes */ - for (i = 0; i < ZSTD_REP_NUM; i++) - seqStorePtr->rep[i] = repToConfirm[i]; - - /* Fill the hash table for the block compressor */ - ZSTD_ldm_limitTableUpdate(ctx, anchor); - ZSTD_ldm_fillFastTables(ctx, anchor); - - /* Call block compressor and get remaining literals */ - lastLiterals = blockCompressor(ctx, anchor, ip - anchor); - ctx->nextToUpdate = (U32)(ip - base); - - /* Update repToConfirm with the new offset */ - for (i = ZSTD_REP_NUM - 1; i > 0; i--) - repToConfirm[i] = repToConfirm[i-1]; - repToConfirm[0] = offset; - - /* Store the sequence with the leftover literals */ - ZSTD_storeSeq(seqStorePtr, lastLiterals, ip - lastLiterals, - offset + ZSTD_REP_MOVE, mLength - MINMATCH); - } - - /* Insert the current entry into the hash table */ - ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, - (U32)(lastHashed - base), - ldmParams); - - /* Fill the hash table from lastHashed+1 to ip+mLength */ - assert(ip + backwardMatchLength == lastHashed); - if (ip + mLength < ilimit) { - rollingHash = ZSTD_ldm_fillLdmHashTable( - ldmState, rollingHash, lastHashed, - ip + mLength, base, hBits, - ldmParams); - lastHashed = ip + mLength - 1; - } - ip += mLength; - anchor = ip; - - /* check immediate repcode */ - while (ip < ilimit) { - U32 const current2 = (U32)(ip-base); - U32 const repIndex2 = current2 - repToConfirm[1]; - const BYTE* repMatch2 = repIndex2 < dictLimit ? - dictBase + repIndex2 : base + repIndex2; - if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & - (repIndex2 > lowestIndex)) /* intentional overflow */ - && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { - const BYTE* const repEnd2 = repIndex2 < dictLimit ? - dictEnd : iend; - size_t const repLength2 = - ZSTD_count_2segments(ip+4, repMatch2+4, iend, - repEnd2, lowPrefixPtr) + 4; - - U32 tmpOffset = repToConfirm[1]; - repToConfirm[1] = repToConfirm[0]; - repToConfirm[0] = tmpOffset; - - ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH); - - /* Fill the hash table from lastHashed+1 to ip+repLength2*/ - if (ip + repLength2 < ilimit) { - rollingHash = ZSTD_ldm_fillLdmHashTable( - ldmState, rollingHash, lastHashed, - ip + repLength2, base, hBits, - ldmParams); - lastHashed = ip + repLength2 - 1; - } - ip += repLength2; - anchor = ip; - continue; - } - break; - } - } - - /* Overwrite rep */ - for (i = 0; i < ZSTD_REP_NUM; i++) - seqStorePtr->rep[i] = repToConfirm[i]; - - ZSTD_ldm_limitTableUpdate(ctx, anchor); - ZSTD_ldm_fillFastTables(ctx, anchor); - - /* Call the block compressor one last time on the last literals */ - lastLiterals = blockCompressor(ctx, anchor, iend - anchor); - ctx->nextToUpdate = (U32)(iend - base); - - /* Restore seqStorePtr->rep */ - for (i = 0; i < ZSTD_REP_NUM; i++) - seqStorePtr->rep[i] = savedRep[i]; - - /* Return the last literals size */ - return lastLiterals; -} - -static size_t ZSTD_compressBlock_ldm_extDict(ZSTD_CCtx* ctx, - const void* src, size_t srcSize) -{ - return ZSTD_compressBlock_ldm_extDict_generic(ctx, src, srcSize); -} - static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr, const BYTE* anchor, size_t lastLLSize) { diff --git a/lib/compress/zstd_ldm.c b/lib/compress/zstd_ldm.c new file mode 100644 index 000000000..4b6d0871a --- /dev/null +++ b/lib/compress/zstd_ldm.c @@ -0,0 +1,702 @@ +/* + * 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). + */ + +#include "zstd_ldm.h" + +#include "zstd_fast.h" /* ZSTD_fillHashTable() */ +#include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */ + +#define LDM_BUCKET_SIZE_LOG 3 +#define LDM_MIN_MATCH_LENGTH 64 +#define LDM_HASH_LOG 20 +#define LDM_HASH_CHAR_OFFSET 10 + +size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm) +{ + ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX); + params->enableLdm = enableLdm>0; + params->hashLog = LDM_HASH_LOG; + params->bucketSizeLog = LDM_BUCKET_SIZE_LOG; + params->minMatchLength = LDM_MIN_MATCH_LENGTH; + params->hashEveryLog = ZSTD_LDM_HASHEVERYLOG_NOTSET; + return 0; +} + +void ZSTD_ldm_adjustParameters(ldmParams_t* params, U32 windowLog) +{ + if (params->hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET) { + params->hashEveryLog = + windowLog < params->hashLog ? 0 : windowLog - params->hashLog; + } + params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog); +} + +size_t ZSTD_ldm_getTableSize(U32 hashLog, U32 bucketSizeLog) { + size_t const ldmHSize = ((size_t)1) << hashLog; + size_t const ldmBucketSizeLog = MIN(bucketSizeLog, hashLog); + size_t const ldmBucketSize = + ((size_t)1) << (hashLog - ldmBucketSizeLog); + return ldmBucketSize + (ldmHSize * (sizeof(ldmEntry_t))); +} + +/** ZSTD_ldm_getSmallHash() : + * numBits should be <= 32 + * If numBits==0, returns 0. + * @return : the most significant numBits of value. */ +static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits) +{ + assert(numBits <= 32); + return numBits == 0 ? 0 : (U32)(value >> (64 - numBits)); +} + +/** ZSTD_ldm_getChecksum() : + * numBitsToDiscard should be <= 32 + * @return : the next most significant 32 bits after numBitsToDiscard */ +static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard) +{ + assert(numBitsToDiscard <= 32); + return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF; +} + +/** ZSTD_ldm_getTag() ; + * Given the hash, returns the most significant numTagBits bits + * after (32 + hbits) bits. + * + * If there are not enough bits remaining, return the last + * numTagBits bits. */ +static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits) +{ + assert(numTagBits <= 32 && hbits <= 32); + if (32 - hbits < numTagBits) { + return hash & ((1 << numTagBits) - 1); + } else { + return (hash >> (32 - hbits - numTagBits)) & ((1 << numTagBits) - 1); + } +} + +/** ZSTD_ldm_getBucket() : + * Returns a pointer to the start of the bucket associated with hash. */ +static ldmEntry_t* ZSTD_ldm_getBucket( + ldmState_t* ldmState, size_t hash, ldmParams_t const ldmParams) +{ + return ldmState->hashTable + (hash << ldmParams.bucketSizeLog); +} + +/** ZSTD_ldm_insertEntry() : + * Insert the entry with corresponding hash into the hash table */ +static void ZSTD_ldm_insertEntry(ldmState_t* ldmState, + size_t const hash, const ldmEntry_t entry, + ldmParams_t const ldmParams) +{ + BYTE* const bucketOffsets = ldmState->bucketOffsets; + *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry; + bucketOffsets[hash]++; + bucketOffsets[hash] &= (1 << ldmParams.bucketSizeLog) - 1; +} + +/** ZSTD_ldm_makeEntryAndInsertByTag() : + * + * Gets the small hash, checksum, and tag from the rollingHash. + * + * If the tag matches (1 << ldmParams.hashEveryLog)-1, then + * creates an ldmEntry from the offset, and inserts it into the hash table. + * + * hBits is the length of the small hash, which is the most significant hBits + * of rollingHash. The checksum is the next 32 most significant bits, followed + * by ldmParams.hashEveryLog bits that make up the tag. */ +static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState, + U64 const rollingHash, + U32 const hBits, + U32 const offset, + ldmParams_t const ldmParams) +{ + U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog); + U32 const tagMask = (1 << ldmParams.hashEveryLog) - 1; + if (tag == tagMask) { + U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits); + U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); + ldmEntry_t entry; + entry.offset = offset; + entry.checksum = checksum; + ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams); + } +} + +/** ZSTD_ldm_getRollingHash() : + * Get a 64-bit hash using the first len bytes from buf. + * + * Giving bytes s = s_1, s_2, ... s_k, the hash is defined to be + * H(s) = s_1*(a^(k-1)) + s_2*(a^(k-2)) + ... + s_k*(a^0) + * + * where the constant a is defined to be prime8bytes. + * + * The implementation adds an offset to each byte, so + * H(s) = (s_1 + HASH_CHAR_OFFSET)*(a^(k-1)) + ... */ +static U64 ZSTD_ldm_getRollingHash(const BYTE* buf, U32 len) +{ + U64 ret = 0; + U32 i; + for (i = 0; i < len; i++) { + ret *= prime8bytes; + ret += buf[i] + LDM_HASH_CHAR_OFFSET; + } + return ret; +} + +/** ZSTD_ldm_ipow() : + * Return base^exp. */ +static U64 ZSTD_ldm_ipow(U64 base, U64 exp) +{ + U64 ret = 1; + while (exp) { + if (exp & 1) { ret *= base; } + exp >>= 1; + base *= base; + } + return ret; +} + +U64 ZSTD_ldm_getHashPower(U32 minMatchLength) { + assert(minMatchLength >= ZSTD_LDM_MINMATCH_MIN); + return ZSTD_ldm_ipow(prime8bytes, minMatchLength - 1); +} + +/** ZSTD_ldm_updateHash() : + * Updates hash by removing toRemove and adding toAdd. */ +static U64 ZSTD_ldm_updateHash(U64 hash, BYTE toRemove, BYTE toAdd, U64 hashPower) +{ + hash -= ((toRemove + LDM_HASH_CHAR_OFFSET) * hashPower); + hash *= prime8bytes; + hash += toAdd + LDM_HASH_CHAR_OFFSET; + return hash; +} + +/** ZSTD_ldm_countBackwardsMatch() : + * Returns the number of bytes that match backwards before pIn and pMatch. + * + * We count only bytes where pMatch >= pBase and pIn >= pAnchor. */ +static size_t ZSTD_ldm_countBackwardsMatch( + const BYTE* pIn, const BYTE* pAnchor, + const BYTE* pMatch, const BYTE* pBase) +{ + size_t matchLength = 0; + while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) { + pIn--; + pMatch--; + matchLength++; + } + return matchLength; +} + +/** ZSTD_ldm_fillFastTables() : + * + * Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies. + * This is similar to ZSTD_loadDictionaryContent. + * + * The tables for the other strategies are filled within their + * block compressors. */ +static size_t ZSTD_ldm_fillFastTables(ZSTD_CCtx* zc, const void* end) +{ + const BYTE* const iend = (const BYTE*)end; + const U32 mls = zc->appliedParams.cParams.searchLength; + + switch(zc->appliedParams.cParams.strategy) + { + case ZSTD_fast: + ZSTD_fillHashTable(zc, iend, mls); + zc->nextToUpdate = (U32)(iend - zc->base); + break; + + case ZSTD_dfast: + ZSTD_fillDoubleHashTable(zc, iend, mls); + zc->nextToUpdate = (U32)(iend - zc->base); + break; + + case ZSTD_greedy: + case ZSTD_lazy: + case ZSTD_lazy2: + case ZSTD_btlazy2: + case ZSTD_btopt: + case ZSTD_btultra: + break; + default: + assert(0); /* not possible : not a valid strategy id */ + } + + return 0; +} + +/** ZSTD_ldm_fillLdmHashTable() : + * + * Fills hashTable from (lastHashed + 1) to iend (non-inclusive). + * lastHash is the rolling hash that corresponds to lastHashed. + * + * Returns the rolling hash corresponding to position iend-1. */ +static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state, + U64 lastHash, const BYTE* lastHashed, + const BYTE* iend, const BYTE* base, + U32 hBits, ldmParams_t const ldmParams) +{ + U64 rollingHash = lastHash; + const BYTE* cur = lastHashed + 1; + + while (cur < iend) { + rollingHash = ZSTD_ldm_updateHash(rollingHash, cur[-1], + cur[ldmParams.minMatchLength-1], + state->hashPower); + ZSTD_ldm_makeEntryAndInsertByTag(state, + rollingHash, hBits, + (U32)(cur - base), ldmParams); + ++cur; + } + return rollingHash; +} + + +/** ZSTD_ldm_limitTableUpdate() : + * + * Sets cctx->nextToUpdate to a position corresponding closer to anchor + * if it is far way + * (after a long match, only update tables a limited amount). */ +static void ZSTD_ldm_limitTableUpdate(ZSTD_CCtx* cctx, const BYTE* anchor) +{ + U32 const current = (U32)(anchor - cctx->base); + if (current > cctx->nextToUpdate + 1024) { + cctx->nextToUpdate = + current - MIN(512, current - cctx->nextToUpdate - 1024); + } +} + +typedef size_t (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize); +/* defined in zstd_compress.c */ +ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict); + +FORCE_INLINE_TEMPLATE +size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx, + const void* src, size_t srcSize) +{ + ldmState_t* const ldmState = &(cctx->ldmState); + const ldmParams_t ldmParams = cctx->appliedParams.ldmParams; + const U64 hashPower = ldmState->hashPower; + const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog; + const U32 ldmBucketSize = (1 << ldmParams.bucketSizeLog); + const U32 ldmTagMask = (1 << ldmParams.hashEveryLog) - 1; + seqStore_t* const seqStorePtr = &(cctx->seqStore); + const BYTE* const base = cctx->base; + const BYTE* const istart = (const BYTE*)src; + const BYTE* ip = istart; + const BYTE* anchor = istart; + const U32 lowestIndex = cctx->dictLimit; + const BYTE* const lowest = base + lowestIndex; + const BYTE* const iend = istart + srcSize; + const BYTE* const ilimit = iend - ldmParams.minMatchLength; + + const ZSTD_blockCompressor blockCompressor = + ZSTD_selectBlockCompressor(cctx->appliedParams.cParams.strategy, 0); + U32* const repToConfirm = seqStorePtr->repToConfirm; + U32 savedRep[ZSTD_REP_NUM]; + U64 rollingHash = 0; + const BYTE* lastHashed = NULL; + size_t i, lastLiterals; + + /* Save seqStorePtr->rep and copy repToConfirm */ + for (i = 0; i < ZSTD_REP_NUM; i++) + savedRep[i] = repToConfirm[i] = seqStorePtr->rep[i]; + + /* Main Search Loop */ + while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ + size_t mLength; + U32 const current = (U32)(ip - base); + size_t forwardMatchLength = 0, backwardMatchLength = 0; + ldmEntry_t* bestEntry = NULL; + if (ip != istart) { + rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0], + lastHashed[ldmParams.minMatchLength], + hashPower); + } else { + rollingHash = ZSTD_ldm_getRollingHash(ip, ldmParams.minMatchLength); + } + lastHashed = ip; + + /* Do not insert and do not look for a match */ + if (ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog) != + ldmTagMask) { + ip++; + continue; + } + + /* Get the best entry and compute the match lengths */ + { + ldmEntry_t* const bucket = + ZSTD_ldm_getBucket(ldmState, + ZSTD_ldm_getSmallHash(rollingHash, hBits), + ldmParams); + ldmEntry_t* cur; + size_t bestMatchLength = 0; + U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); + + for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) { + const BYTE* const pMatch = cur->offset + base; + size_t curForwardMatchLength, curBackwardMatchLength, + curTotalMatchLength; + if (cur->checksum != checksum || cur->offset <= lowestIndex) { + continue; + } + + curForwardMatchLength = ZSTD_count(ip, pMatch, iend); + if (curForwardMatchLength < ldmParams.minMatchLength) { + continue; + } + curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch( + ip, anchor, pMatch, lowest); + curTotalMatchLength = curForwardMatchLength + + curBackwardMatchLength; + + if (curTotalMatchLength > bestMatchLength) { + bestMatchLength = curTotalMatchLength; + forwardMatchLength = curForwardMatchLength; + backwardMatchLength = curBackwardMatchLength; + bestEntry = cur; + } + } + } + + /* No match found -- continue searching */ + if (bestEntry == NULL) { + ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, + hBits, current, + ldmParams); + ip++; + continue; + } + + /* Match found */ + mLength = forwardMatchLength + backwardMatchLength; + ip -= backwardMatchLength; + + /* Call the block compressor on the remaining literals */ + { + U32 const matchIndex = bestEntry->offset; + const BYTE* const match = base + matchIndex - backwardMatchLength; + U32 const offset = (U32)(ip - match); + + /* Overwrite rep codes */ + for (i = 0; i < ZSTD_REP_NUM; i++) + seqStorePtr->rep[i] = repToConfirm[i]; + + /* Fill tables for block compressor */ + ZSTD_ldm_limitTableUpdate(cctx, anchor); + ZSTD_ldm_fillFastTables(cctx, anchor); + + /* Call block compressor and get remaining literals */ + lastLiterals = blockCompressor(cctx, anchor, ip - anchor); + cctx->nextToUpdate = (U32)(ip - base); + + /* Update repToConfirm with the new offset */ + for (i = ZSTD_REP_NUM - 1; i > 0; i--) + repToConfirm[i] = repToConfirm[i-1]; + repToConfirm[0] = offset; + + /* Store the sequence with the leftover literals */ + ZSTD_storeSeq(seqStorePtr, lastLiterals, ip - lastLiterals, + offset + ZSTD_REP_MOVE, mLength - MINMATCH); + } + + /* Insert the current entry into the hash table */ + ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, + (U32)(lastHashed - base), + ldmParams); + + assert(ip + backwardMatchLength == lastHashed); + + /* Fill the hash table from lastHashed+1 to ip+mLength*/ + /* Heuristic: don't need to fill the entire table at end of block */ + if (ip + mLength < ilimit) { + rollingHash = ZSTD_ldm_fillLdmHashTable( + ldmState, rollingHash, lastHashed, + ip + mLength, base, hBits, ldmParams); + lastHashed = ip + mLength - 1; + } + ip += mLength; + anchor = ip; + /* Check immediate repcode */ + while ( (ip < ilimit) + && ( (repToConfirm[1] > 0) && (repToConfirm[1] <= (U32)(ip-lowest)) + && (MEM_read32(ip) == MEM_read32(ip - repToConfirm[1])) )) { + + size_t const rLength = ZSTD_count(ip+4, ip+4-repToConfirm[1], + iend) + 4; + /* Swap repToConfirm[1] <=> repToConfirm[0] */ + { + U32 const tmpOff = repToConfirm[1]; + repToConfirm[1] = repToConfirm[0]; + repToConfirm[0] = tmpOff; + } + + ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH); + + /* Fill the hash table from lastHashed+1 to ip+rLength*/ + if (ip + rLength < ilimit) { + rollingHash = ZSTD_ldm_fillLdmHashTable( + ldmState, rollingHash, lastHashed, + ip + rLength, base, hBits, ldmParams); + lastHashed = ip + rLength - 1; + } + ip += rLength; + anchor = ip; + } + } + + /* Overwrite rep */ + for (i = 0; i < ZSTD_REP_NUM; i++) + seqStorePtr->rep[i] = repToConfirm[i]; + + ZSTD_ldm_limitTableUpdate(cctx, anchor); + ZSTD_ldm_fillFastTables(cctx, anchor); + + lastLiterals = blockCompressor(cctx, anchor, iend - anchor); + cctx->nextToUpdate = (U32)(iend - base); + + /* Restore seqStorePtr->rep */ + for (i = 0; i < ZSTD_REP_NUM; i++) + seqStorePtr->rep[i] = savedRep[i]; + + /* Return the last literals size */ + return lastLiterals; +} + +size_t ZSTD_compressBlock_ldm(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +{ + return ZSTD_compressBlock_ldm_generic(ctx, src, srcSize); +} + +static size_t ZSTD_compressBlock_ldm_extDict_generic( + ZSTD_CCtx* ctx, + const void* src, size_t srcSize) +{ + ldmState_t* const ldmState = &(ctx->ldmState); + const ldmParams_t ldmParams = ctx->appliedParams.ldmParams; + const U64 hashPower = ldmState->hashPower; + const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog; + const U32 ldmBucketSize = (1 << ldmParams.bucketSizeLog); + const U32 ldmTagMask = (1 << ldmParams.hashEveryLog) - 1; + seqStore_t* const seqStorePtr = &(ctx->seqStore); + const BYTE* const base = ctx->base; + const BYTE* const dictBase = ctx->dictBase; + const BYTE* const istart = (const BYTE*)src; + const BYTE* ip = istart; + const BYTE* anchor = istart; + const U32 lowestIndex = ctx->lowLimit; + const BYTE* const dictStart = dictBase + lowestIndex; + const U32 dictLimit = ctx->dictLimit; + const BYTE* const lowPrefixPtr = base + dictLimit; + const BYTE* const dictEnd = dictBase + dictLimit; + const BYTE* const iend = istart + srcSize; + const BYTE* const ilimit = iend - ldmParams.minMatchLength; + + const ZSTD_blockCompressor blockCompressor = + ZSTD_selectBlockCompressor(ctx->appliedParams.cParams.strategy, 1); + U32* const repToConfirm = seqStorePtr->repToConfirm; + U32 savedRep[ZSTD_REP_NUM]; + U64 rollingHash = 0; + const BYTE* lastHashed = NULL; + size_t i, lastLiterals; + + /* Save seqStorePtr->rep and copy repToConfirm */ + for (i = 0; i < ZSTD_REP_NUM; i++) { + savedRep[i] = repToConfirm[i] = seqStorePtr->rep[i]; + } + + /* Search Loop */ + while (ip < ilimit) { /* < instead of <=, because (ip+1) */ + size_t mLength; + const U32 current = (U32)(ip-base); + size_t forwardMatchLength = 0, backwardMatchLength = 0; + ldmEntry_t* bestEntry = NULL; + if (ip != istart) { + rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0], + lastHashed[ldmParams.minMatchLength], + hashPower); + } else { + rollingHash = ZSTD_ldm_getRollingHash(ip, ldmParams.minMatchLength); + } + lastHashed = ip; + + if (ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog) != + ldmTagMask) { + /* Don't insert and don't look for a match */ + ip++; + continue; + } + + /* Get the best entry and compute the match lengths */ + { + ldmEntry_t* const bucket = + ZSTD_ldm_getBucket(ldmState, + ZSTD_ldm_getSmallHash(rollingHash, hBits), + ldmParams); + ldmEntry_t* cur; + size_t bestMatchLength = 0; + U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); + + for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) { + const BYTE* const curMatchBase = + cur->offset < dictLimit ? dictBase : base; + const BYTE* const pMatch = curMatchBase + cur->offset; + const BYTE* const matchEnd = + cur->offset < dictLimit ? dictEnd : iend; + const BYTE* const lowMatchPtr = + cur->offset < dictLimit ? dictStart : lowPrefixPtr; + size_t curForwardMatchLength, curBackwardMatchLength, + curTotalMatchLength; + + if (cur->checksum != checksum || cur->offset <= lowestIndex) { + continue; + } + + curForwardMatchLength = ZSTD_count_2segments( + ip, pMatch, iend, + matchEnd, lowPrefixPtr); + if (curForwardMatchLength < ldmParams.minMatchLength) { + continue; + } + curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch( + ip, anchor, pMatch, lowMatchPtr); + curTotalMatchLength = curForwardMatchLength + + curBackwardMatchLength; + + if (curTotalMatchLength > bestMatchLength) { + bestMatchLength = curTotalMatchLength; + forwardMatchLength = curForwardMatchLength; + backwardMatchLength = curBackwardMatchLength; + bestEntry = cur; + } + } + } + + /* No match found -- continue searching */ + if (bestEntry == NULL) { + ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, + (U32)(lastHashed - base), + ldmParams); + ip++; + continue; + } + + /* Match found */ + mLength = forwardMatchLength + backwardMatchLength; + ip -= backwardMatchLength; + + /* Call the block compressor on the remaining literals */ + { + /* ip = current - backwardMatchLength + * The match is at (bestEntry->offset - backwardMatchLength) */ + U32 const matchIndex = bestEntry->offset; + U32 const offset = current - matchIndex; + + /* Overwrite rep codes */ + for (i = 0; i < ZSTD_REP_NUM; i++) + seqStorePtr->rep[i] = repToConfirm[i]; + + /* Fill the hash table for the block compressor */ + ZSTD_ldm_limitTableUpdate(ctx, anchor); + ZSTD_ldm_fillFastTables(ctx, anchor); + + /* Call block compressor and get remaining literals */ + lastLiterals = blockCompressor(ctx, anchor, ip - anchor); + ctx->nextToUpdate = (U32)(ip - base); + + /* Update repToConfirm with the new offset */ + for (i = ZSTD_REP_NUM - 1; i > 0; i--) + repToConfirm[i] = repToConfirm[i-1]; + repToConfirm[0] = offset; + + /* Store the sequence with the leftover literals */ + ZSTD_storeSeq(seqStorePtr, lastLiterals, ip - lastLiterals, + offset + ZSTD_REP_MOVE, mLength - MINMATCH); + } + + /* Insert the current entry into the hash table */ + ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, + (U32)(lastHashed - base), + ldmParams); + + /* Fill the hash table from lastHashed+1 to ip+mLength */ + assert(ip + backwardMatchLength == lastHashed); + if (ip + mLength < ilimit) { + rollingHash = ZSTD_ldm_fillLdmHashTable( + ldmState, rollingHash, lastHashed, + ip + mLength, base, hBits, + ldmParams); + lastHashed = ip + mLength - 1; + } + ip += mLength; + anchor = ip; + + /* check immediate repcode */ + while (ip < ilimit) { + U32 const current2 = (U32)(ip-base); + U32 const repIndex2 = current2 - repToConfirm[1]; + const BYTE* repMatch2 = repIndex2 < dictLimit ? + dictBase + repIndex2 : base + repIndex2; + if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & + (repIndex2 > lowestIndex)) /* intentional overflow */ + && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { + const BYTE* const repEnd2 = repIndex2 < dictLimit ? + dictEnd : iend; + size_t const repLength2 = + ZSTD_count_2segments(ip+4, repMatch2+4, iend, + repEnd2, lowPrefixPtr) + 4; + + U32 tmpOffset = repToConfirm[1]; + repToConfirm[1] = repToConfirm[0]; + repToConfirm[0] = tmpOffset; + + ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH); + + /* Fill the hash table from lastHashed+1 to ip+repLength2*/ + if (ip + repLength2 < ilimit) { + rollingHash = ZSTD_ldm_fillLdmHashTable( + ldmState, rollingHash, lastHashed, + ip + repLength2, base, hBits, + ldmParams); + lastHashed = ip + repLength2 - 1; + } + ip += repLength2; + anchor = ip; + continue; + } + break; + } + } + + /* Overwrite rep */ + for (i = 0; i < ZSTD_REP_NUM; i++) + seqStorePtr->rep[i] = repToConfirm[i]; + + ZSTD_ldm_limitTableUpdate(ctx, anchor); + ZSTD_ldm_fillFastTables(ctx, anchor); + + /* Call the block compressor one last time on the last literals */ + lastLiterals = blockCompressor(ctx, anchor, iend - anchor); + ctx->nextToUpdate = (U32)(iend - base); + + /* Restore seqStorePtr->rep */ + for (i = 0; i < ZSTD_REP_NUM; i++) + seqStorePtr->rep[i] = savedRep[i]; + + /* Return the last literals size */ + return lastLiterals; +} + +size_t ZSTD_compressBlock_ldm_extDict(ZSTD_CCtx* ctx, + const void* src, size_t srcSize) +{ + return ZSTD_compressBlock_ldm_extDict_generic(ctx, src, srcSize); +} diff --git a/lib/compress/zstd_ldm.h b/lib/compress/zstd_ldm.h new file mode 100644 index 000000000..7a6248399 --- /dev/null +++ b/lib/compress/zstd_ldm.h @@ -0,0 +1,67 @@ +/* + * 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). + */ + +#ifndef ZSTD_LDM_H +#define ZSTD_LDM_H + +#include "zstd_compress.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +/*-************************************* +* Long distance matching +***************************************/ + +#define ZSTD_LDM_WINDOW_LOG 27 +#define ZSTD_LDM_HASHEVERYLOG_NOTSET 9999 + +/** ZSTD_compressBlock_ldm_generic() : + * + * This is a block compressor intended for long distance matching. + * + * The function searches for matches of length at least + * ldmParams.minMatchLength using a hash table in cctx->ldmState. + * Matches can be at a distance of up to cParams.windowLog. + * + * Upon finding a match, the unmatched literals are compressed using a + * ZSTD_blockCompressor (depending on the strategy in the compression + * parameters), which stores the matched sequences. The "long distance" + * match is then stored with the remaining literals from the + * ZSTD_blockCompressor. */ +size_t ZSTD_compressBlock_ldm(ZSTD_CCtx* cctx, const void* src, size_t srcSize); +size_t ZSTD_compressBlock_ldm_extDict(ZSTD_CCtx* ctx, + const void* src, size_t srcSize); + +/** ZSTD_ldm_initializeParameters() : + * Initialize the long distance matching parameters to their default values. */ +size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm); + +/** ZSTD_ldm_getTableSize() : + * Estimate the space needed for long distance matching tables. */ +size_t ZSTD_ldm_getTableSize(U32 hashLog, U32 bucketSizeLog); + +/** ZSTD_ldm_getTableSize() : + * Return prime8bytes^(minMatchLength-1) */ +U64 ZSTD_ldm_getHashPower(U32 minMatchLength); + +/** ZSTD_ldm_adjustParameters() : + * If the params->hashEveryLog is not set, set it to its default value based on + * windowLog and params->hashLog. + * + * Ensures that params->bucketSizeLog is <= params->hashLog (setting it to + * params->hashLog if it is not). */ +void ZSTD_ldm_adjustParameters(ldmParams_t* params, U32 windowLog); + +#if defined (__cplusplus) +} +#endif + +#endif /* ZSTD_FAST_H */ From 3128e03be69b9d3db054a3765ae1310c7b3666f6 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 8 Sep 2017 00:09:23 -0700 Subject: [PATCH 115/248] updated license header to clarify dual-license meaning as "or" --- examples/dictionary_compression.c | 1 + examples/dictionary_decompression.c | 1 + examples/multiple_streaming_compression.c | 1 + examples/simple_compression.c | 1 + examples/simple_decompression.c | 1 + examples/streaming_compression.c | 1 + examples/streaming_decompression.c | 1 + lib/common/compiler.h | 1 + lib/common/error_private.c | 1 + lib/common/error_private.h | 1 + lib/common/mem.h | 1 + lib/common/pool.c | 1 + lib/common/pool.h | 1 + lib/common/zstd_common.c | 1 + lib/common/zstd_errors.h | 1 + lib/common/zstd_internal.h | 1 + lib/compress/zstd_compress.c | 1 + lib/compress/zstd_compress.h | 1 + lib/compress/zstd_double_fast.c | 1 + lib/compress/zstd_double_fast.h | 1 + lib/compress/zstd_fast.c | 1 + lib/compress/zstd_fast.h | 1 + lib/compress/zstd_lazy.c | 1 + lib/compress/zstd_lazy.h | 1 + lib/compress/zstd_opt.c | 1 + lib/compress/zstd_opt.h | 1 + lib/compress/zstdmt_compress.c | 1 + lib/compress/zstdmt_compress.h | 1 + lib/decompress/zstd_decompress.c | 1 + lib/deprecated/zbuff.h | 1 + lib/deprecated/zbuff_common.c | 1 + lib/deprecated/zbuff_compress.c | 1 + lib/deprecated/zbuff_decompress.c | 1 + lib/dictBuilder/cover.c | 1 + lib/dictBuilder/zdict.c | 1 + lib/dictBuilder/zdict.h | 1 + lib/legacy/zstd_legacy.h | 1 + lib/legacy/zstd_v01.c | 1 + lib/legacy/zstd_v01.h | 1 + lib/legacy/zstd_v02.c | 1 + lib/legacy/zstd_v02.h | 1 + lib/legacy/zstd_v03.c | 1 + lib/legacy/zstd_v03.h | 1 + lib/legacy/zstd_v04.c | 1 + lib/legacy/zstd_v04.h | 1 + lib/legacy/zstd_v05.c | 1 + lib/legacy/zstd_v05.h | 1 + lib/legacy/zstd_v06.c | 1 + lib/legacy/zstd_v06.h | 1 + lib/legacy/zstd_v07.c | 1 + lib/legacy/zstd_v07.h | 1 + lib/zstd.h | 1 + programs/bench.c | 1 + programs/bench.h | 1 + programs/datagen.c | 1 + programs/datagen.h | 1 + programs/dibio.c | 1 + programs/dibio.h | 1 + programs/fileio.c | 1 + programs/fileio.h | 1 + programs/platform.h | 1 + programs/util.h | 1 + programs/zstdcli.c | 1 + tests/datagencli.c | 3 ++- tests/decodecorpus.c | 3 ++- tests/fullbench.c | 3 ++- tests/fuzzer.c | 3 ++- tests/invalidDictionaries.c | 1 + tests/legacy.c | 1 + tests/longmatch.c | 3 ++- tests/namespaceTest.c | 1 + tests/paramgrill.c | 3 ++- tests/poolTests.c | 1 + tests/roundTripCrash.c | 1 + tests/symbols.c | 1 + tests/zbufftest.c | 3 ++- tests/zstreamtest.c | 1 + zlibWrapper/gzcompatibility.h | 1 + zlibWrapper/zstd_zlibwrapper.c | 1 + zlibWrapper/zstd_zlibwrapper.h | 1 + 80 files changed, 87 insertions(+), 7 deletions(-) diff --git a/examples/dictionary_compression.c b/examples/dictionary_compression.c index 17acec98d..97bf8cb5e 100644 --- a/examples/dictionary_compression.c +++ b/examples/dictionary_compression.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/examples/dictionary_decompression.c b/examples/dictionary_decompression.c index 345c968c3..07e6e24c6 100644 --- a/examples/dictionary_decompression.c +++ b/examples/dictionary_decompression.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/examples/multiple_streaming_compression.c b/examples/multiple_streaming_compression.c index 7bfa133ee..e395aefbc 100644 --- a/examples/multiple_streaming_compression.c +++ b/examples/multiple_streaming_compression.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/examples/simple_compression.c b/examples/simple_compression.c index 95853faa6..9ade424a2 100644 --- a/examples/simple_compression.c +++ b/examples/simple_compression.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/examples/simple_decompression.c b/examples/simple_decompression.c index 9e9fcc9ed..c1818a95c 100644 --- a/examples/simple_decompression.c +++ b/examples/simple_decompression.c @@ -5,6 +5,7 @@ * 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 // malloc, exit diff --git a/examples/streaming_compression.c b/examples/streaming_compression.c index ac7ee7687..f76364d84 100644 --- a/examples/streaming_compression.c +++ b/examples/streaming_compression.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/examples/streaming_decompression.c b/examples/streaming_decompression.c index 76dd85169..504a5e316 100644 --- a/examples/streaming_decompression.c +++ b/examples/streaming_decompression.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/common/compiler.h b/lib/common/compiler.h index d7225c443..3a7553c38 100644 --- a/lib/common/compiler.h +++ b/lib/common/compiler.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTD_COMPILER_H diff --git a/lib/common/error_private.c b/lib/common/error_private.c index b5b14b509..8045e445e 100644 --- a/lib/common/error_private.c +++ b/lib/common/error_private.c @@ -5,6 +5,7 @@ * 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. */ /* The purpose of this file is to have a single list of error strings embedded in binary */ diff --git a/lib/common/error_private.h b/lib/common/error_private.h index a55bce847..0d2fa7e34 100644 --- a/lib/common/error_private.h +++ b/lib/common/error_private.h @@ -5,6 +5,7 @@ * 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. */ /* Note : this module is expected to remain private, do not expose it */ diff --git a/lib/common/mem.h b/lib/common/mem.h index df85404fb..23335c314 100644 --- a/lib/common/mem.h +++ b/lib/common/mem.h @@ -5,6 +5,7 @@ * 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. */ #ifndef MEM_H_MODULE diff --git a/lib/common/pool.c b/lib/common/pool.c index d7080f034..5f19f331b 100644 --- a/lib/common/pool.c +++ b/lib/common/pool.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/common/pool.h b/lib/common/pool.h index 411b73e11..08c63715a 100644 --- a/lib/common/pool.h +++ b/lib/common/pool.h @@ -5,6 +5,7 @@ * 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. */ #ifndef POOL_H diff --git a/lib/common/zstd_common.c b/lib/common/zstd_common.c index 1155c60c4..c2041053b 100644 --- a/lib/common/zstd_common.c +++ b/lib/common/zstd_common.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/common/zstd_errors.h b/lib/common/zstd_errors.h index a69387b71..bde4304c9 100644 --- a/lib/common/zstd_errors.h +++ b/lib/common/zstd_errors.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTD_ERRORS_H_398273423 diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index b8564d2bf..1e20619ab 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTD_CCOMMON_H_MODULE diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index ebb73f398..63dfc36e9 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/compress/zstd_compress.h b/lib/compress/zstd_compress.h index a136a949d..0408be8f6 100644 --- a/lib/compress/zstd_compress.h +++ b/lib/compress/zstd_compress.h @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/compress/zstd_double_fast.c b/lib/compress/zstd_double_fast.c index 437e9a2c6..62368736a 100644 --- a/lib/compress/zstd_double_fast.c +++ b/lib/compress/zstd_double_fast.c @@ -5,6 +5,7 @@ * 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 "zstd_double_fast.h" diff --git a/lib/compress/zstd_double_fast.h b/lib/compress/zstd_double_fast.h index 64f8bfef6..1b7db5b3c 100644 --- a/lib/compress/zstd_double_fast.h +++ b/lib/compress/zstd_double_fast.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTD_DOUBLE_FAST_H diff --git a/lib/compress/zstd_fast.c b/lib/compress/zstd_fast.c index 82ab15a4c..22f2c10e5 100644 --- a/lib/compress/zstd_fast.c +++ b/lib/compress/zstd_fast.c @@ -5,6 +5,7 @@ * 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 "zstd_fast.h" diff --git a/lib/compress/zstd_fast.h b/lib/compress/zstd_fast.h index f18b4617e..e15a4ce6a 100644 --- a/lib/compress/zstd_fast.h +++ b/lib/compress/zstd_fast.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTD_FAST_H diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c index 00ec1e286..d12619ac4 100644 --- a/lib/compress/zstd_lazy.c +++ b/lib/compress/zstd_lazy.c @@ -5,6 +5,7 @@ * 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 "zstd_lazy.h" diff --git a/lib/compress/zstd_lazy.h b/lib/compress/zstd_lazy.h index 451cddf96..b83c475b2 100644 --- a/lib/compress/zstd_lazy.h +++ b/lib/compress/zstd_lazy.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTD_LAZY_H diff --git a/lib/compress/zstd_opt.c b/lib/compress/zstd_opt.c index 03e945516..cf5dbd86e 100644 --- a/lib/compress/zstd_opt.c +++ b/lib/compress/zstd_opt.c @@ -5,6 +5,7 @@ * 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 "zstd_opt.h" diff --git a/lib/compress/zstd_opt.h b/lib/compress/zstd_opt.h index 0991a1f13..a304bd661 100644 --- a/lib/compress/zstd_opt.h +++ b/lib/compress/zstd_opt.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTD_OPT_H diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 20122f359..ae8c63cc6 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/compress/zstdmt_compress.h b/lib/compress/zstdmt_compress.h index 31e8c8db3..11880dfd3 100644 --- a/lib/compress/zstdmt_compress.h +++ b/lib/compress/zstdmt_compress.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTDMT_COMPRESS_H diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index ada773b9a..00e2fb4a2 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/deprecated/zbuff.h b/lib/deprecated/zbuff.h index e6ea84ad3..a93115da4 100644 --- a/lib/deprecated/zbuff.h +++ b/lib/deprecated/zbuff.h @@ -5,6 +5,7 @@ * 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. */ /* *************************************************************** diff --git a/lib/deprecated/zbuff_common.c b/lib/deprecated/zbuff_common.c index 2de45bec1..661b9b0e1 100644 --- a/lib/deprecated/zbuff_common.c +++ b/lib/deprecated/zbuff_common.c @@ -5,6 +5,7 @@ * 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. */ /*-************************************* diff --git a/lib/deprecated/zbuff_compress.c b/lib/deprecated/zbuff_compress.c index 4444e95d8..8adbaec26 100644 --- a/lib/deprecated/zbuff_compress.c +++ b/lib/deprecated/zbuff_compress.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/deprecated/zbuff_decompress.c b/lib/deprecated/zbuff_decompress.c index a819d7f40..923c22b73 100644 --- a/lib/deprecated/zbuff_decompress.c +++ b/lib/deprecated/zbuff_decompress.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index 61497846b..f6500b3d8 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -5,6 +5,7 @@ * 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. */ /* ***************************************************************************** diff --git a/lib/dictBuilder/zdict.c b/lib/dictBuilder/zdict.c index 8e6aa9c1c..b76e7695a 100644 --- a/lib/dictBuilder/zdict.c +++ b/lib/dictBuilder/zdict.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/dictBuilder/zdict.h b/lib/dictBuilder/zdict.h index 3d72a465e..5f0000b1c 100644 --- a/lib/dictBuilder/zdict.h +++ b/lib/dictBuilder/zdict.h @@ -5,6 +5,7 @@ * 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. */ #ifndef DICTBUILDER_H_001 diff --git a/lib/legacy/zstd_legacy.h b/lib/legacy/zstd_legacy.h index 1126e2466..487ff0b28 100644 --- a/lib/legacy/zstd_legacy.h +++ b/lib/legacy/zstd_legacy.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTD_LEGACY_H diff --git a/lib/legacy/zstd_v01.c b/lib/legacy/zstd_v01.c index 45f421ae6..70003cbed 100644 --- a/lib/legacy/zstd_v01.c +++ b/lib/legacy/zstd_v01.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/legacy/zstd_v01.h b/lib/legacy/zstd_v01.h index a91c6a133..42f0897c7 100644 --- a/lib/legacy/zstd_v01.h +++ b/lib/legacy/zstd_v01.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTD_V01_H_28739879432 diff --git a/lib/legacy/zstd_v02.c b/lib/legacy/zstd_v02.c index dc1ec0e7c..b935a4d18 100644 --- a/lib/legacy/zstd_v02.c +++ b/lib/legacy/zstd_v02.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/legacy/zstd_v02.h b/lib/legacy/zstd_v02.h index 63cb3b8d5..0dde7a637 100644 --- a/lib/legacy/zstd_v02.h +++ b/lib/legacy/zstd_v02.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTD_V02_H_4174539423 diff --git a/lib/legacy/zstd_v03.c b/lib/legacy/zstd_v03.c index 8257de7e6..35370dd0c 100644 --- a/lib/legacy/zstd_v03.c +++ b/lib/legacy/zstd_v03.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/legacy/zstd_v03.h b/lib/legacy/zstd_v03.h index e38e0109b..b4449e299 100644 --- a/lib/legacy/zstd_v03.h +++ b/lib/legacy/zstd_v03.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTD_V03_H_298734209782 diff --git a/lib/legacy/zstd_v04.c b/lib/legacy/zstd_v04.c index 951561a6c..1b5f6f3b0 100644 --- a/lib/legacy/zstd_v04.c +++ b/lib/legacy/zstd_v04.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/legacy/zstd_v04.h b/lib/legacy/zstd_v04.h index a7d662330..6391631fc 100644 --- a/lib/legacy/zstd_v04.h +++ b/lib/legacy/zstd_v04.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTD_V04_H_91868324769238 diff --git a/lib/legacy/zstd_v05.c b/lib/legacy/zstd_v05.c index 4a1d4d4bd..23188f504 100644 --- a/lib/legacy/zstd_v05.c +++ b/lib/legacy/zstd_v05.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/legacy/zstd_v05.h b/lib/legacy/zstd_v05.h index a333bd127..b68fd578e 100644 --- a/lib/legacy/zstd_v05.h +++ b/lib/legacy/zstd_v05.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTDv05_H diff --git a/lib/legacy/zstd_v06.c b/lib/legacy/zstd_v06.c index a285a0901..62683f994 100644 --- a/lib/legacy/zstd_v06.c +++ b/lib/legacy/zstd_v06.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/legacy/zstd_v06.h b/lib/legacy/zstd_v06.h index ee043a179..fb4eb37c8 100644 --- a/lib/legacy/zstd_v06.h +++ b/lib/legacy/zstd_v06.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTDv06_H diff --git a/lib/legacy/zstd_v07.c b/lib/legacy/zstd_v07.c index ad392e90b..aad9b1f65 100644 --- a/lib/legacy/zstd_v07.c +++ b/lib/legacy/zstd_v07.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/lib/legacy/zstd_v07.h b/lib/legacy/zstd_v07.h index 68d18e963..6591cd301 100644 --- a/lib/legacy/zstd_v07.h +++ b/lib/legacy/zstd_v07.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTDv07_H_235446 diff --git a/lib/zstd.h b/lib/zstd.h index e69702f69..8817ef945 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -5,6 +5,7 @@ * 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. */ #if defined (__cplusplus) extern "C" { diff --git a/programs/bench.c b/programs/bench.c index d5c04c698..a691f7313 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/programs/bench.h b/programs/bench.h index 5f8d61a25..860d1ab21 100644 --- a/programs/bench.h +++ b/programs/bench.h @@ -5,6 +5,7 @@ * 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. */ diff --git a/programs/datagen.c b/programs/datagen.c index b1da8e78b..a489d6af0 100644 --- a/programs/datagen.c +++ b/programs/datagen.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/programs/datagen.h b/programs/datagen.h index 5b1b7c47c..2fcc980e5 100644 --- a/programs/datagen.h +++ b/programs/datagen.h @@ -5,6 +5,7 @@ * 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. */ diff --git a/programs/dibio.c b/programs/dibio.c index ab2dc285a..ffc78451d 100644 --- a/programs/dibio.c +++ b/programs/dibio.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/programs/dibio.h b/programs/dibio.h index 0227239b2..ac2424491 100644 --- a/programs/dibio.h +++ b/programs/dibio.h @@ -5,6 +5,7 @@ * 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. */ /* This library is designed for a single-threaded console application. diff --git a/programs/fileio.c b/programs/fileio.c index 65b4c7579..e8aba4b52 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/programs/fileio.h b/programs/fileio.h index 8008e97dd..748103685 100644 --- a/programs/fileio.h +++ b/programs/fileio.h @@ -5,6 +5,7 @@ * 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. */ diff --git a/programs/platform.h b/programs/platform.h index e9629a0fa..a4d7850fd 100644 --- a/programs/platform.h +++ b/programs/platform.h @@ -5,6 +5,7 @@ * 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. */ #ifndef PLATFORM_H_MODULE diff --git a/programs/util.h b/programs/util.h index 384dec1bd..e79fab42d 100644 --- a/programs/util.h +++ b/programs/util.h @@ -5,6 +5,7 @@ * 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. */ #ifndef UTIL_H_MODULE diff --git a/programs/zstdcli.c b/programs/zstdcli.c index e7eb71db6..c5f7f578d 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/tests/datagencli.c b/tests/datagencli.c index bf9601f20..4814974e2 100644 --- a/tests/datagencli.c +++ b/tests/datagencli.c @@ -1,10 +1,11 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2015-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. */ diff --git a/tests/decodecorpus.c b/tests/decodecorpus.c index 23166bd67..a06571328 100644 --- a/tests/decodecorpus.c +++ b/tests/decodecorpus.c @@ -1,10 +1,11 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2017-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 diff --git a/tests/fullbench.c b/tests/fullbench.c index 78a70940f..2361debf8 100644 --- a/tests/fullbench.c +++ b/tests/fullbench.c @@ -1,10 +1,11 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2015-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. */ diff --git a/tests/fuzzer.c b/tests/fuzzer.c index b23498705..108eeaf48 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -1,10 +1,11 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2015-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. */ diff --git a/tests/invalidDictionaries.c b/tests/invalidDictionaries.c index 83fe439d4..b23db036f 100644 --- a/tests/invalidDictionaries.c +++ b/tests/invalidDictionaries.c @@ -5,6 +5,7 @@ * 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 diff --git a/tests/legacy.c b/tests/legacy.c index 962b2c9c3..46a8206c4 100644 --- a/tests/legacy.c +++ b/tests/legacy.c @@ -5,6 +5,7 @@ * 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. */ /* diff --git a/tests/longmatch.c b/tests/longmatch.c index ef79337f5..ed3861571 100644 --- a/tests/longmatch.c +++ b/tests/longmatch.c @@ -1,10 +1,11 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2017-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. */ diff --git a/tests/namespaceTest.c b/tests/namespaceTest.c index 6f6c74fd6..5b7095f67 100644 --- a/tests/namespaceTest.c +++ b/tests/namespaceTest.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/tests/paramgrill.c b/tests/paramgrill.c index c39434998..1bc48f401 100644 --- a/tests/paramgrill.c +++ b/tests/paramgrill.c @@ -1,10 +1,11 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2015-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. */ diff --git a/tests/poolTests.c b/tests/poolTests.c index f3d5c382a..00ee83015 100644 --- a/tests/poolTests.c +++ b/tests/poolTests.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/tests/roundTripCrash.c b/tests/roundTripCrash.c index f17f2f33f..180fa9b6f 100644 --- a/tests/roundTripCrash.c +++ b/tests/roundTripCrash.c @@ -5,6 +5,7 @@ * 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. */ /* diff --git a/tests/symbols.c b/tests/symbols.c index f08542dbf..c0bed2e5d 100644 --- a/tests/symbols.c +++ b/tests/symbols.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/tests/zbufftest.c b/tests/zbufftest.c index fe08fdab5..e64c886a5 100644 --- a/tests/zbufftest.c +++ b/tests/zbufftest.c @@ -1,10 +1,11 @@ /* - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2015-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. */ diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 1f3aeea4c..d7b2e197a 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/zlibWrapper/gzcompatibility.h b/zlibWrapper/gzcompatibility.h index 98ddf1f11..ea8d50c82 100644 --- a/zlibWrapper/gzcompatibility.h +++ b/zlibWrapper/gzcompatibility.h @@ -5,6 +5,7 @@ * 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. */ diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 836587f2b..c5fbdf98e 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -5,6 +5,7 @@ * 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. */ diff --git a/zlibWrapper/zstd_zlibwrapper.h b/zlibWrapper/zstd_zlibwrapper.h index 9c923cb18..f828d3191 100644 --- a/zlibWrapper/zstd_zlibwrapper.h +++ b/zlibWrapper/zstd_zlibwrapper.h @@ -5,6 +5,7 @@ * 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. */ #ifndef ZSTD_ZLIBWRAPPER_H From 058ed2ad3349187e985a481b6db654952729c307 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 9 Sep 2017 01:03:29 -0700 Subject: [PATCH 116/248] ZSTD_decodingBufferSize_min() supporting function for bufferless streaming API (ZSTD_decompressContinue()) makes it possible to correctly size a round buffer for decoding using this API. also : added field blockSizeMax within ZSTD_frameHeader, as it's a necessary information to know when to restart at beginning of decoding buffer. --- doc/zstd_manual.html | 74 +++++++++++++++++-------------- lib/decompress/zstd_decompress.c | 21 ++++++--- lib/zstd.h | 75 +++++++++++++++++++------------- tests/fuzzer.c | 10 +++++ zlibWrapper/Makefile | 2 +- 5 files changed, 113 insertions(+), 69 deletions(-) diff --git a/doc/zstd_manual.html b/doc/zstd_manual.html index 83b75fd86..c1c6d41a4 100644 --- a/doc/zstd_manual.html +++ b/doc/zstd_manual.html @@ -703,40 +703,53 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned lo A ZSTD_DCtx object can be re-used multiple times. First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader(). - It fills a ZSTD_frameHeader structure with important information to correctly decode the frame, - such as minimum rolling buffer size to allocate to decompress data (`windowSize`), - and the dictionary ID in use. - (Note : content size is optional, it may not be present. 0 means : content size unknown). - Note that these values could be wrong, either because of data malformation, or because an attacker is spoofing deliberate false information. - As a consequence, check that values remain within valid application range, especially `windowSize`, before allocation. - Each application can set its own limit, depending on local restrictions. - For extended interoperability, it is recommended to support windowSize of at least 8 MB. Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough. Data fragment must be large enough to ensure successful decoding. - `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough. + `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough. @result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled. >0 : `srcSize` is too small, please provide at least @result bytes on next attempt. errorCode, which can be tested using ZSTD_isError(). - Start decompression, with ZSTD_decompressBegin(). + It fills a ZSTD_frameHeader structure with important information to correctly decode the frame, + such as the dictionary ID, content size, or maximum back-reference distance (`windowSize`). + Note that these values could be wrong, either because of data corruption, or because a 3rd party deliberately spoofs false information. + As a consequence, check that values remain within valid application range. + For example, do not allocate memory blindly, check that `windowSize` is within expectation. + Each application can set its own limits, depending on local restrictions. + For extended interoperability, it is recommended to support `windowSize` of at least 8 MB. + + ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize` bytes. + ZSTD_decompressContinue() is very sensitive to contiguity, + if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place, + or that previous contiguous segment is large enough to properly handle maximum back-reference distance. + There are multiple ways to guarantee this condition. + + The most memory efficient way is to use a round buffer of sufficient size. + Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(), + which can @return an error code if required value is too large for current system (in 32-bits mode). + In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one, + up to the moment there is not enough room left in the buffer to guarantee decoding another full block, + which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`. + At which point, decoding can resume from the beginning of the buffer. + Note that already decoded data stored in the buffer should be flushed before being overwritten. + + There are alternatives possible, for example using two or more buffers of size `windowSize` each, though they consume more memory. + + Finally, if you control the compression process, you can also ignore all buffer size rules, + as long as the encoder and decoder progress in "lock-step", + aka use exactly the same buffer sizes, break contiguity at the same place, etc. + + Once buffers are setup, start decompression, with ZSTD_decompressBegin(). If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict(). - Alternatively, you can copy a prepared context, using ZSTD_copyDCtx(). Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue(). ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail. - @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity). - It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some metadata item. + @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity). + It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item. It can also be an error code, which can be tested with ZSTD_isError(). - ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize`. - They should preferably be located contiguously, prior to current block. - Alternatively, a round buffer of sufficient size is also possible. Sufficient size is determined by frame parameters. - ZSTD_decompressContinue() is very sensitive to contiguity, - if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place, - or that previous contiguous segment is large enough to properly handle maximum back-reference. - A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero. Context can then be reset to start a new decompression. @@ -746,32 +759,27 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned lo == Special case : skippable frames Skippable frames allow integration of user-defined data into a flow of concatenated frames. - Skippable frames will be ignored (skipped) by a decompressor. The format of skippable frames is as follows : + Skippable frames will be ignored (skipped) by decompressor. + The format of skippable frames is as follows : a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits c) Frame Content - any content (User Data) of length equal to Frame Size - For skippable frames ZSTD_decompressContinue() always returns 0. - For skippable frames ZSTD_getFrameHeader() returns fparamsPtr->windowLog==0 what means that a frame is skippable. - Note : If fparamsPtr->frameContentSize==0, it is ambiguous: the frame might actually be a Zstd encoded frame with no content. - For purposes of decompression, it is valid in both cases to skip the frame using - ZSTD_findFrameCompressedSize to find its size in bytes. - It also returns Frame Size as fparamsPtr->frameContentSize. + For skippable frames ZSTD_getFrameHeader() returns zfhPtr->frameType==ZSTD_skippableFrame. + For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content.

    Buffer-less streaming decompression functions

    typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e;
     typedef struct {
    -    unsigned long long frameContentSize; /* ZSTD_CONTENTSIZE_UNKNOWN means this field is not available. 0 means "empty" */
    +    unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */
         unsigned long long windowSize;       /* can be very large, up to <= frameContentSize */
    +    unsigned blockSizeMax;
         ZSTD_frameType_e frameType;          /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */
         unsigned headerSize;
         unsigned dictID;
         unsigned checksumFlag;
     } ZSTD_frameHeader;
     size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize);   /**< doesn't consume input */
    -size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx);
    -size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
    -size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
    -void   ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx);
    +size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize);
     

    typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
     

    @@ -1034,7 +1042,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t

    Raw zstd block functions

    size_t ZSTD_getBlockSize   (const ZSTD_CCtx* cctx);
     size_t ZSTD_compressBlock  (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
     size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
    -size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize);  /**< insert block into `dctx` history. Useful for uncompressed blocks */
    +size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize);  /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression */
     

    diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 00e2fb4a2..aeac17d19 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -297,7 +297,6 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src memset(zfhPtr, 0, sizeof(*zfhPtr)); zfhPtr->frameContentSize = MEM_readLE32((const char *)src + 4); zfhPtr->frameType = ZSTD_skippableFrame; - zfhPtr->windowSize = 0; return 0; } return ERROR(prefix_unknown); @@ -350,6 +349,7 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src zfhPtr->frameType = ZSTD_frame; zfhPtr->frameContentSize = frameContentSize; zfhPtr->windowSize = windowSize; + zfhPtr->blockSizeMax = (unsigned) MIN(windowSize, ZSTD_BLOCKSIZE_MAX); zfhPtr->dictID = dictID; zfhPtr->checksumFlag = checksumFlag; } @@ -2117,7 +2117,7 @@ unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict) * ZSTD_getFrameHeader(), which will provide a more precise error code. */ unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize) { - ZSTD_frameHeader zfp = { 0, 0, ZSTD_frame, 0, 0, 0 }; + ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 }; size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize); if (ZSTD_isError(hError)) return 0; return zfp.dictID; @@ -2224,17 +2224,28 @@ size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds) return ZSTD_sizeof_DCtx(zds); } +size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize) +{ + size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX); + unsigned long long const neededRBSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2); + unsigned long long const neededSize = MIN(frameContentSize, neededRBSize); + size_t const minRBSize = (size_t) neededSize; + if ((unsigned long long)minRBSize != neededSize) return ERROR(frameParameter_windowTooLarge); + return minRBSize; +} + size_t ZSTD_estimateDStreamSize(size_t windowSize) { size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX); size_t const inBuffSize = blockSize; /* no block can be larger */ - size_t const outBuffSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2); + //size_t const outBuffSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2); + size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN); return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize; } ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize) { - U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; + U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable */ ZSTD_frameHeader zfh; size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize); if (ZSTD_isError(err)) return err; @@ -2350,7 +2361,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_windowTooLarge); /* Adapt buffer sizes to frame header instructions */ - { size_t const blockSize = (size_t)(MIN(zds->fParams.windowSize, ZSTD_BLOCKSIZE_MAX)); + { size_t const blockSize = zds->fParams.blockSizeMax; size_t const neededOutSize = (size_t)(zds->fParams.windowSize + blockSize + WILDCOPY_OVERLENGTH * 2); zds->blockSize = blockSize; if ((zds->inBuffSize < blockSize) || (zds->outBuffSize < neededOutSize)) { diff --git a/lib/zstd.h b/lib/zstd.h index 8817ef945..e97782c38 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -812,40 +812,53 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapaci A ZSTD_DCtx object can be re-used multiple times. First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader(). - It fills a ZSTD_frameHeader structure with important information to correctly decode the frame, - such as minimum rolling buffer size to allocate to decompress data (`windowSize`), - and the dictionary ID in use. - (Note : content size is optional, it may not be present. 0 means : content size unknown). - Note that these values could be wrong, either because of data malformation, or because an attacker is spoofing deliberate false information. - As a consequence, check that values remain within valid application range, especially `windowSize`, before allocation. - Each application can set its own limit, depending on local restrictions. - For extended interoperability, it is recommended to support windowSize of at least 8 MB. Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough. Data fragment must be large enough to ensure successful decoding. - `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough. + `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough. @result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled. >0 : `srcSize` is too small, please provide at least @result bytes on next attempt. errorCode, which can be tested using ZSTD_isError(). - Start decompression, with ZSTD_decompressBegin(). + It fills a ZSTD_frameHeader structure with important information to correctly decode the frame, + such as the dictionary ID, content size, or maximum back-reference distance (`windowSize`). + Note that these values could be wrong, either because of data corruption, or because a 3rd party deliberately spoofs false information. + As a consequence, check that values remain within valid application range. + For example, do not allocate memory blindly, check that `windowSize` is within expectation. + Each application can set its own limits, depending on local restrictions. + For extended interoperability, it is recommended to support `windowSize` of at least 8 MB. + + ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize` bytes. + ZSTD_decompressContinue() is very sensitive to contiguity, + if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place, + or that previous contiguous segment is large enough to properly handle maximum back-reference distance. + There are multiple ways to guarantee this condition. + + The most memory efficient way is to use a round buffer of sufficient size. + Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(), + which can @return an error code if required value is too large for current system (in 32-bits mode). + In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one, + up to the moment there is not enough room left in the buffer to guarantee decoding another full block, + which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`. + At which point, decoding can resume from the beginning of the buffer. + Note that already decoded data stored in the buffer should be flushed before being overwritten. + + There are alternatives possible, for example using two or more buffers of size `windowSize` each, though they consume more memory. + + Finally, if you control the compression process, you can also ignore all buffer size rules, + as long as the encoder and decoder progress in "lock-step", + aka use exactly the same buffer sizes, break contiguity at the same place, etc. + + Once buffers are setup, start decompression, with ZSTD_decompressBegin(). If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict(). - Alternatively, you can copy a prepared context, using ZSTD_copyDCtx(). Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue(). ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail. - @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity). - It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some metadata item. + @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity). + It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item. It can also be an error code, which can be tested with ZSTD_isError(). - ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize`. - They should preferably be located contiguously, prior to current block. - Alternatively, a round buffer of sufficient size is also possible. Sufficient size is determined by frame parameters. - ZSTD_decompressContinue() is very sensitive to contiguity, - if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place, - or that previous contiguous segment is large enough to properly handle maximum back-reference. - A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero. Context can then be reset to start a new decompression. @@ -855,36 +868,38 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapaci == Special case : skippable frames == Skippable frames allow integration of user-defined data into a flow of concatenated frames. - Skippable frames will be ignored (skipped) by a decompressor. The format of skippable frames is as follows : + Skippable frames will be ignored (skipped) by decompressor. + The format of skippable frames is as follows : a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits c) Frame Content - any content (User Data) of length equal to Frame Size - For skippable frames ZSTD_decompressContinue() always returns 0. - For skippable frames ZSTD_getFrameHeader() returns fparamsPtr->windowLog==0 what means that a frame is skippable. - Note : If fparamsPtr->frameContentSize==0, it is ambiguous: the frame might actually be a Zstd encoded frame with no content. - For purposes of decompression, it is valid in both cases to skip the frame using - ZSTD_findFrameCompressedSize to find its size in bytes. - It also returns Frame Size as fparamsPtr->frameContentSize. + For skippable frames ZSTD_getFrameHeader() returns zfhPtr->frameType==ZSTD_skippableFrame. + For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content. */ /*===== Buffer-less streaming decompression functions =====*/ typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e; typedef struct { - unsigned long long frameContentSize; /* ZSTD_CONTENTSIZE_UNKNOWN means this field is not available. 0 means "empty" */ + unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */ unsigned long long windowSize; /* can be very large, up to <= frameContentSize */ + unsigned blockSizeMax; ZSTD_frameType_e frameType; /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */ unsigned headerSize; unsigned dictID; unsigned checksumFlag; } ZSTD_frameHeader; ZSTDLIB_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */ +ZSTDLIB_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); + ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); ZSTDLIB_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); -ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + +/* misc */ +ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e; ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); @@ -1188,7 +1203,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( ZSTDLIB_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx); ZSTDLIB_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); ZSTDLIB_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -ZSTDLIB_API size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert block into `dctx` history. Useful for uncompressed blocks */ +ZSTDLIB_API size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression */ #endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */ diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 108eeaf48..2bc5c9dfe 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -1384,6 +1384,16 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD } /* streaming decompression test */ + /* ensure memory requirement is good enough (should always be true) */ + { ZSTD_frameHeader zfh; + CHECK( ZSTD_getFrameHeader(&zfh, cBuffer, ZSTD_frameHeaderSize_max), + "ZSTD_getFrameHeader(): error retrieving frame information"); + { size_t const roundBuffSize = ZSTD_decodingBufferSize_min(zfh.windowSize, zfh.frameContentSize); + CHECK_Z(roundBuffSize); + CHECK((roundBuffSize > totalTestSize) && (zfh.frameContentSize!=ZSTD_CONTENTSIZE_UNKNOWN), + "ZSTD_decodingBufferSize_min() requires more memory (%u) than necessary (%u)", + (U32)roundBuffSize, (U32)totalTestSize ); + } } if (dictSize<8) dictSize=0, dict=NULL; /* disable dictionary */ CHECK_Z( ZSTD_decompressBegin_usingDict(dctx, dict, dictSize) ); totalCSize = 0; diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index 4e8fb4a32..c1896f8b8 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -34,7 +34,7 @@ EXT = endif -all: clean fitblk example zwrapbench minigzip +all: fitblk example zwrapbench minigzip test: example fitblk example_zstd fitblk_zstd zwrapbench minigzip minigzip_zstd ./example From b3f33ccfb3b4fcc73df82126fd5ecfb751268fc6 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 9 Sep 2017 14:37:28 -0700 Subject: [PATCH 117/248] use ZSTD_decodingBufferSize_min() inside ZSTD_decompressStream() Use same definition as public one minor : reduce allocated buffer size in some cases (when frameContentSize is known and == windowSize) --- lib/decompress/zstd_decompress.c | 53 ++++++++++++++++++++------------ tests/zstreamtest.c | 10 ++++-- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index aeac17d19..5158d3f32 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -102,7 +102,8 @@ struct ZSTD_DCtx_s const void* dictEnd; /* end of previous segment */ size_t expected; ZSTD_frameHeader fParams; - blockType_e bType; /* used in ZSTD_decompressContinue(), to transfer blockType between header decoding and block decoding stages */ + U64 decodedSize; + blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */ ZSTD_dStage stage; U32 litEntropy; U32 fseEntropy; @@ -127,7 +128,6 @@ struct ZSTD_DCtx_s size_t outBuffSize; size_t outStart; size_t outEnd; - size_t blockSize; size_t lhSize; void* legacyContext; U32 previousLegacyVersion; @@ -153,6 +153,7 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) { dctx->expected = ZSTD_frameHeaderSize_prefix; dctx->stage = ZSTDds_getFrameHeaderSize; + dctx->decodedSize = 0; dctx->previousDstEnd = NULL; dctx->base = NULL; dctx->vBase = NULL; @@ -172,13 +173,13 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) { ZSTD_decompressBegin(dctx); /* cannot fail */ - dctx->staticSize = 0; + dctx->staticSize = 0; dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; - dctx->ddict = NULL; - dctx->ddictLocal = NULL; - dctx->inBuff = NULL; - dctx->inBuffSize = 0; - dctx->outBuffSize= 0; + dctx->ddict = NULL; + dctx->ddictLocal = NULL; + dctx->inBuff = NULL; + dctx->inBuffSize = 0; + dctx->outBuffSize = 0; dctx->streamStage = zdss_init; } @@ -1771,9 +1772,16 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c return ERROR(corruption_detected); } if (ZSTD_isError(rSize)) return rSize; + DEBUGLOG(5, "decoded size from block : %u", (U32)rSize); + dctx->decodedSize += rSize; if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize); if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */ + DEBUGLOG(4, "decoded size from frame : %u", (U32)dctx->decodedSize); + if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) { + if (dctx->decodedSize != dctx->fParams.frameContentSize) { + return ERROR(corruption_detected); + } } if (dctx->fParams.checksumFlag) { /* another round for frame checksum */ dctx->expected = 4; dctx->stage = ZSTDds_checkChecksum; @@ -1789,8 +1797,11 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c return rSize; } case ZSTDds_checkChecksum: + DEBUGLOG(4, "case ZSTDds_checkChecksum"); + assert(srcSize == 4); /* guaranteed by dctx->expected */ { U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); - U32 const check32 = MEM_readLE32(src); /* srcSize == 4, guaranteed by dctx->expected */ + U32 const check32 = MEM_readLE32(src); + DEBUGLOG(4, "calculated %08X :: %08X read", h32, check32); if (check32 != h32) return ERROR(checksum_wrong); dctx->expected = 0; dctx->stage = ZSTDds_getFrameHeaderSize; @@ -2361,15 +2372,14 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_windowTooLarge); /* Adapt buffer sizes to frame header instructions */ - { size_t const blockSize = zds->fParams.blockSizeMax; - size_t const neededOutSize = (size_t)(zds->fParams.windowSize + blockSize + WILDCOPY_OVERLENGTH * 2); - zds->blockSize = blockSize; - if ((zds->inBuffSize < blockSize) || (zds->outBuffSize < neededOutSize)) { - size_t const bufferSize = blockSize + neededOutSize; + { size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */); + size_t const neededOutBuffSize = ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize); + if ((zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize)) { + size_t const bufferSize = neededInBuffSize + neededOutBuffSize; DEBUGLOG(4, "inBuff : from %u to %u", - (U32)zds->inBuffSize, (U32)blockSize); + (U32)zds->inBuffSize, (U32)neededInBuffSize); DEBUGLOG(4, "outBuff : from %u to %u", - (U32)zds->outBuffSize, (U32)neededOutSize); + (U32)zds->outBuffSize, (U32)neededOutBuffSize); if (zds->staticSize) { /* static DCtx */ DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize); assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */ @@ -2382,9 +2392,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB zds->inBuff = (char*)ZSTD_malloc(bufferSize, zds->customMem); if (zds->inBuff == NULL) return ERROR(memory_allocation); } - zds->inBuffSize = blockSize; + zds->inBuffSize = neededInBuffSize; zds->outBuff = zds->inBuff + zds->inBuffSize; - zds->outBuffSize = neededOutSize; + zds->outBuffSize = neededOutBuffSize; } } zds->streamStage = zdss_read; /* fall-through */ @@ -2442,8 +2452,13 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB zds->outStart += flushedSize; if (flushedSize == toFlushSize) { /* flush completed */ zds->streamStage = zdss_read; - if (zds->outStart + zds->blockSize > zds->outBuffSize) + if ( (zds->outBuffSize < zds->fParams.frameContentSize) + && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) { + DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)", + (int)(zds->outBuffSize - zds->outStart), + (U32)zds->fParams.blockSizeMax); zds->outStart = zds->outEnd = 0; + } break; } } /* cannot complete flush */ diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index d7b2e197a..8c8adc62d 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -909,10 +909,16 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres inBuff.size = inBuff.pos + readCSrcSize; outBuff.size = inBuff.pos + dstBuffSize; decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff); - CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult)); + if (ZSTD_getErrorCode(decompressionResult) == ZSTD_error_checksum_wrong) { + DISPLAY("checksum error : \n"); + findDiff(copyBuffer, dstBuffer, totalTestSize); + } + CHECK( ZSTD_isError(decompressionResult), "decompression error : %s", + ZSTD_getErrorName(decompressionResult) ); } CHECK (decompressionResult != 0, "frame not fully decoded"); - CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size") + CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", + (U32)outBuff.pos, (U32)totalTestSize); CHECK (inBuff.pos != cSize, "compressed data should be fully read") { U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0); if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize); From ce31004f205bb5dcb5ba6766b86009ffbcc90f00 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 11 Sep 2017 13:12:52 -0700 Subject: [PATCH 118/248] fix following suggestions by @terrelln --- doc/zstd_manual.html | 2 +- lib/decompress/zstd_decompress.c | 1 - lib/zstd.h | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/zstd_manual.html b/doc/zstd_manual.html index c1c6d41a4..1c298726c 100644 --- a/doc/zstd_manual.html +++ b/doc/zstd_manual.html @@ -779,7 +779,7 @@ typedef struct { unsigned checksumFlag; } ZSTD_frameHeader; size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize);
    /**< doesn't consume input */ -size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); +size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */

    typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
     

    diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 5158d3f32..aa4c58d91 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -2249,7 +2249,6 @@ size_t ZSTD_estimateDStreamSize(size_t windowSize) { size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX); size_t const inBuffSize = blockSize; /* no block can be larger */ - //size_t const outBuffSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2); size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN); return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize; } diff --git a/lib/zstd.h b/lib/zstd.h index e97782c38..7695776f5 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -889,7 +889,7 @@ typedef struct { unsigned checksumFlag; } ZSTD_frameHeader; ZSTDLIB_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */ -ZSTDLIB_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); +ZSTDLIB_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */ ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); From 0d6ecc72a3158b41446970cfcf2f1f1d45b72f41 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 11 Sep 2017 14:09:34 -0700 Subject: [PATCH 119/248] makes it possible to compile libzstd in single-thread mode without zstdmt_compress.c (#819) --- NEWS | 1 + circle.yml | 2 +- lib/.gitignore | 1 + lib/Makefile | 11 ++++++++- lib/compress/zstd_compress.c | 43 ++++++++++++++++++++-------------- lib/compress/zstd_compress.h | 6 ++++- lib/compress/zstdmt_compress.h | 16 +++++++++++++ 7 files changed, 60 insertions(+), 20 deletions(-) diff --git a/NEWS b/NEWS index c659e1f47..1300c80d4 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ license : changed /examples license to BSD + GPLv2 license : fix a few header files to reflect new license (#825) fix : 32-bits build can now decode large offsets (levels 21+) fix : a rare compression bug when compression generates very large distances (only possible at --ultra -22) +build: fix : no-multithread variant compiles without pool.c dependency, reported by Mitchell Blank Jr (@mitchblank) (#819) build: better compatibility with reproducible builds, by Bernhard M. Wiedemann (@bmwiedemann) (#818) v1.3.1 diff --git a/circle.yml b/circle.yml index 8c2bd30d3..e89d548ac 100644 --- a/circle.yml +++ b/circle.yml @@ -9,7 +9,7 @@ dependencies: test: override: - ? | - if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then cc -v; make all && make clean; fi && + if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then cc -v; make all && make clean && make -C lib libzstd-nomt && make clean; fi && if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make gnu90build && make clean; fi : parallel: true diff --git a/lib/.gitignore b/lib/.gitignore index b43a8543a..4cd50ac61 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -1,2 +1,3 @@ # make install artefact libzstd.pc +libzstd-nomt diff --git a/lib/Makefile b/lib/Makefile index 6de1450b3..cdfdc5cdf 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -101,10 +101,19 @@ lib-release lib-release-mt: DEBUGFLAGS := lib-release: lib lib-release-mt: lib-mt +# Special case : building library in single-thread mode _and_ without zstdmt_compress.c +ZSTDMT_FILES = compress/zstdmt_compress.c +ZSTD_NOMT_FILES = $(filter-out $(ZSTDMT_FILES),$(ZSTD_FILES)) +libzstd-nomt: LDFLAGS += -shared -fPIC -fvisibility=hidden +libzstd-nomt: $(ZSTD_NOMT_FILES) + @echo compiling single-thread dynamic library $(LIBVER) + @echo files : $(ZSTD_NOMT_FILES) + @$(CC) $(FLAGS) $^ $(LDFLAGS) $(SONAME_FLAGS) -o $@ + clean: @$(RM) -r *.dSYM # Mac OS-X specific @$(RM) core *.o *.a *.gcda *.$(SHARED_EXT) *.$(SHARED_EXT).* libzstd.pc - @$(RM) dll/libzstd.dll dll/libzstd.lib + @$(RM) dll/libzstd.dll dll/libzstd.lib libzstd-nomt* @$(RM) common/*.o compress/*.o decompress/*.o dictBuilder/*.o legacy/*.o deprecated/*.o @echo Cleaning library completed diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 63dfc36e9..616a3d581 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -112,23 +112,37 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) cctx->workSpace = NULL; ZSTD_freeCDict(cctx->cdictLocal); cctx->cdictLocal = NULL; +#ifdef ZSTD_MULTITHREAD ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL; +#endif ZSTD_free(cctx, cctx->customMem); return 0; /* reserved as a potential error code in the future */ } + +static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx) +{ +#ifdef ZSTD_MULTITHREAD + return ZSTDMT_sizeof_CCtx(cctx->mtctx); +#else + (void) cctx; + return 0; +#endif +} + + size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) { if (cctx==NULL) return 0; /* support sizeof on NULL */ DEBUGLOG(5, "sizeof(*cctx) : %u", (U32)sizeof(*cctx)); DEBUGLOG(5, "workSpaceSize : %u", (U32)cctx->workSpaceSize); DEBUGLOG(5, "streaming buffers : %u", (U32)(cctx->outBuffSize + cctx->inBuffSize)); - DEBUGLOG(5, "inner MTCTX : %u", (U32)ZSTDMT_sizeof_CCtx(cctx->mtctx)); + DEBUGLOG(5, "inner MTCTX : %u", (U32)ZSTD_sizeof_mtctx(cctx)); return sizeof(*cctx) + cctx->workSpaceSize + ZSTD_sizeof_CDict(cctx->cdictLocal) + cctx->outBuffSize + cctx->inBuffSize - + ZSTDMT_sizeof_CCtx(cctx->mtctx); + + ZSTD_sizeof_mtctx(cctx); } size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) @@ -238,10 +252,6 @@ static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( return ERROR(parameter_outOfBound); \ } } -size_t ZSTDMT_CCtxParam_setMTCtxParameter( - ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value); -size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads); - size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value) { if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); @@ -379,16 +389,25 @@ size_t ZSTD_CCtxParam_setParameter( if (value == 0) return 0; #ifndef ZSTD_MULTITHREAD if (value > 1) return ERROR(parameter_unsupported); -#endif +#else return ZSTDMT_initializeCCtxParameters(params, value); +#endif case ZSTD_p_jobSize : +#ifndef ZSTD_MULTITHREAD + return ERROR(parameter_unsupported); +#else if (params->nbThreads <= 1) return ERROR(parameter_unsupported); return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_sectionSize, value); +#endif case ZSTD_p_overlapSizeLog : +#ifndef ZSTD_MULTITHREAD + return ERROR(parameter_unsupported); +#else if (params->nbThreads <= 1) return ERROR(parameter_unsupported); return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_overlapSectionLog, value); +#endif default: return ERROR(parameter_unsupported); } @@ -2531,16 +2550,6 @@ size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuf return ZSTD_compressStream_generic(zcs, output, input, ZSTD_e_continue); } -/*! ZSTDMT_initCStream_internal() : - * Private use only. Init streaming operation. - * expects params to be valid. - * must receive dict, or cdict, or none, but not both. - * @return : 0, or an error code */ -size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, - const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, - const ZSTD_CDict* cdict, - ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); - size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, ZSTD_outBuffer* output, diff --git a/lib/compress/zstd_compress.h b/lib/compress/zstd_compress.h index 0408be8f6..4da0317a7 100644 --- a/lib/compress/zstd_compress.h +++ b/lib/compress/zstd_compress.h @@ -16,7 +16,9 @@ * Dependencies ***************************************/ #include "zstd_internal.h" -#include "zstdmt_compress.h" +#ifdef ZSTD_MULTITHREAD +# include "zstdmt_compress.h" +#endif #if defined (__cplusplus) extern "C" { @@ -90,7 +92,9 @@ struct ZSTD_CCtx_s { ZSTD_prefixDict prefixDict; /* single-usage dictionary */ /* Multi-threading */ +#ifdef ZSTD_MULTITHREAD ZSTDMT_CCtx* mtctx; +#endif }; diff --git a/lib/compress/zstdmt_compress.h b/lib/compress/zstdmt_compress.h index 11880dfd3..8c59c684f 100644 --- a/lib/compress/zstdmt_compress.h +++ b/lib/compress/zstdmt_compress.h @@ -108,6 +108,22 @@ ZSTDLIB_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, ZSTD_EndDirective endOp); +/* === Private definitions; never ever use directly === */ + +size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value); + +size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads); + +/*! ZSTDMT_initCStream_internal() : + * Private use only. Init streaming operation. + * expects params to be valid. + * must receive dict, or cdict, or none, but not both. + * @return : 0, or an error code */ +size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs, + const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, + const ZSTD_CDict* cdict, + ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); + #if defined (__cplusplus) } From 0d1b54db61e4ca3ed29b5b633561878ead04c196 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Mon, 11 Sep 2017 13:02:09 -0700 Subject: [PATCH 120/248] Explicitly cast raw numerals when left-shifting --- lib/compress/zstd_compress.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 2364eee25..a2bd20751 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -1151,17 +1151,17 @@ static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size, * rescale all indexes to avoid future overflow (indexes are U32) */ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue) { - { U32 const hSize = 1 << zc->appliedParams.cParams.hashLog; + { U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog; ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); } - { U32 const chainSize = (zc->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->appliedParams.cParams.chainLog); + { U32 const chainSize = (zc->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((U32)1 << zc->appliedParams.cParams.chainLog); ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); } - { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0; + { U32 const h3Size = (zc->hashLog3) ? (U32)1 << zc->hashLog3 : 0; ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); } { if (zc->appliedParams.ldmParams.enableLdm) { - U32 const ldmHSize = 1 << zc->appliedParams.ldmParams.hashLog; + U32 const ldmHSize = (U32)1 << zc->appliedParams.ldmParams.hashLog; ZSTD_ldm_reduceTable(zc->ldmState.hashTable, ldmHSize, reducerValue); } } @@ -3163,11 +3163,11 @@ static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard) * numTagBits bits. */ static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits) { - assert(numTagBits <= 32 && hbits <= 32); + assert(numTagBits < 32 && hbits <= 32); if (32 - hbits < numTagBits) { - return hash & ((1 << numTagBits) - 1); + return hash & (((U32)1 << numTagBits) - 1); } else { - return (hash >> (32 - hbits - numTagBits)) & ((1 << numTagBits) - 1); + return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1); } } @@ -3188,7 +3188,7 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState, BYTE* const bucketOffsets = ldmState->bucketOffsets; *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry; bucketOffsets[hash]++; - bucketOffsets[hash] &= (1 << ldmParams.bucketSizeLog) - 1; + bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1; } /** ZSTD_ldm_makeEntryAndInsertByTag() : @@ -3208,7 +3208,7 @@ static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState, ldmParams_t const ldmParams) { U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog); - U32 const tagMask = (1 << ldmParams.hashEveryLog) - 1; + U32 const tagMask = ((U32)1 << ldmParams.hashEveryLog) - 1; if (tag == tagMask) { U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits); U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); @@ -3385,8 +3385,8 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx, const ldmParams_t ldmParams = cctx->appliedParams.ldmParams; const U64 hashPower = ldmState->hashPower; const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog; - const U32 ldmBucketSize = (1 << ldmParams.bucketSizeLog); - const U32 ldmTagMask = (1 << ldmParams.hashEveryLog) - 1; + const U32 ldmBucketSize = ((U32)1 << ldmParams.bucketSizeLog); + const U32 ldmTagMask = ((U32)1 << ldmParams.hashEveryLog) - 1; seqStore_t* const seqStorePtr = &(cctx->seqStore); const BYTE* const base = cctx->base; const BYTE* const istart = (const BYTE*)src; @@ -3585,8 +3585,8 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic( const ldmParams_t ldmParams = ctx->appliedParams.ldmParams; const U64 hashPower = ldmState->hashPower; const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog; - const U32 ldmBucketSize = (1 << ldmParams.bucketSizeLog); - const U32 ldmTagMask = (1 << ldmParams.hashEveryLog) - 1; + const U32 ldmBucketSize = ((U32)1 << ldmParams.bucketSizeLog); + const U32 ldmTagMask = ((U32)1 << ldmParams.hashEveryLog) - 1; seqStore_t* const seqStorePtr = &(ctx->seqStore); const BYTE* const base = ctx->base; const BYTE* const dictBase = ctx->dictBase; From f325ee4e84f2042e8c5747119db9160bcea52e96 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 11 Sep 2017 14:37:03 -0700 Subject: [PATCH 121/248] fixed pass-through warning --- lib/compress/zstd_compress.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 616a3d581..884a4e00d 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -389,6 +389,7 @@ size_t ZSTD_CCtxParam_setParameter( if (value == 0) return 0; #ifndef ZSTD_MULTITHREAD if (value > 1) return ERROR(parameter_unsupported); + return 0; #else return ZSTDMT_initializeCCtxParameters(params, value); #endif From 3306bcb0e623ccd51f9f1049dba8e88c55e1db0d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 11 Sep 2017 15:17:31 -0700 Subject: [PATCH 122/248] fix #820 : GCC v3.x 32-bits doesn't define 64-bits intrinsic resulting in undefined symbol error. Push the requirement to GCC 4 for now. Another solution, proposed by @NWilson, is to use __LONG_MAX__ instead. __LONG_MAX__ is a GCC-specific constant, which value is supposed to depend on underlying target hardware (32/64 bits) Might be better, but seems also more complex, hence more prone to side effects. Keeping the simple solution for now (just rely on __GNUC__) --- lib/compress/zstd_compress.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/compress/zstd_compress.h b/lib/compress/zstd_compress.h index 4da0317a7..d8813782c 100644 --- a/lib/compress/zstd_compress.h +++ b/lib/compress/zstd_compress.h @@ -168,7 +168,7 @@ static unsigned ZSTD_NbCommonBytes (register size_t val) unsigned long r = 0; _BitScanForward64( &r, (U64)val ); return (unsigned)(r>>3); -# elif defined(__GNUC__) && (__GNUC__ >= 3) +# elif defined(__GNUC__) && (__GNUC__ >= 4) return (__builtin_ctzll((U64)val) >> 3); # else static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, @@ -202,7 +202,7 @@ static unsigned ZSTD_NbCommonBytes (register size_t val) unsigned long r = 0; _BitScanReverse64( &r, val ); return (unsigned)(r>>3); -# elif defined(__GNUC__) && (__GNUC__ >= 3) +# elif defined(__GNUC__) && (__GNUC__ >= 4) return (__builtin_clzll(val) >> 3); # else unsigned r; From 3d8e313f64879f4efe91220436bc02da9a95f05b Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Mon, 11 Sep 2017 17:21:28 -0700 Subject: [PATCH 123/248] Reduce ldm hash table size in test --- tests/zstreamtest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index d1993d21a..f80743e67 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1390,7 +1390,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double /* mess with long distance matching parameters */ if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_enableLongDistanceMatching, FUZ_rand(&lseed) & 63, useOpaqueAPI) ); - if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashLog, FUZ_randomClampedLength(&lseed, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX), useOpaqueAPI) ); + if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashLog, FUZ_randomClampedLength(&lseed, ZSTD_HASHLOG_MIN, 23), useOpaqueAPI) ); if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmMinMatch, FUZ_randomClampedLength(&lseed, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX), useOpaqueAPI) ); if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmBucketSizeLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_LDM_BUCKETSIZELOG_MAX), useOpaqueAPI) ); if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashEveryLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN), useOpaqueAPI) ); From 6ab4d5e9041aba962a810ffee191f95897c6208e Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 12 Sep 2017 13:09:08 -0700 Subject: [PATCH 124/248] [bench] Use higher resolution timer on POSIX The timer used was only accurate up to 0.01 seconds. This timer is accurate up to 1 ns. It is a monotonic timer that measures the real time difference, not on CPU time. --- programs/util.h | 87 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 26 deletions(-) diff --git a/programs/util.h b/programs/util.h index e79fab42d..3903db5d8 100644 --- a/programs/util.h +++ b/programs/util.h @@ -118,35 +118,70 @@ static int g_utilDisplayLevel; * Time functions ******************************************/ #if defined(_WIN32) /* Windows */ - typedef LARGE_INTEGER UTIL_freq_t; - typedef LARGE_INTEGER UTIL_time_t; - UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { if (!QueryPerformanceFrequency(ticksPerSecond)) UTIL_DISPLAYLEVEL(1, "ERROR: QueryPerformance not present\n"); } - UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { QueryPerformanceCounter(x); } - UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; } - UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; } + typedef LARGE_INTEGER UTIL_freq_t; + typedef LARGE_INTEGER UTIL_time_t; + UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { if (!QueryPerformanceFrequency(ticksPerSecond)) UTIL_DISPLAYLEVEL(1, "ERROR: QueryPerformance not present\n"); } + UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { QueryPerformanceCounter(x); } + UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; } + UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; } #elif defined(__APPLE__) && defined(__MACH__) - #include - typedef mach_timebase_info_data_t UTIL_freq_t; - typedef U64 UTIL_time_t; - UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* rate) { mach_timebase_info(rate); } - UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { *x = mach_absolute_time(); } - UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t rate, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return (((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom))/1000ULL; } - UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t rate, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return ((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom); } + #include + typedef mach_timebase_info_data_t UTIL_freq_t; + typedef U64 UTIL_time_t; + UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* rate) { mach_timebase_info(rate); } + UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { *x = mach_absolute_time(); } + UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t rate, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return (((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom))/1000ULL; } + UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t rate, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return ((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom); } #elif (PLATFORM_POSIX_VERSION >= 200112L) - #include /* times */ - typedef U64 UTIL_freq_t; - typedef U64 UTIL_time_t; - UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { *ticksPerSecond=sysconf(_SC_CLK_TCK); } - UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { struct tms junk; clock_t newTicks = (clock_t) times(&junk); (void)junk; *x = (UTIL_time_t)newTicks; } - UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL * (clockEnd - clockStart) / ticksPerSecond; } - UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL * (clockEnd - clockStart) / ticksPerSecond; } + #include + typedef struct timespec UTIL_freq_t; + typedef struct timespec UTIL_time_t; + UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* res) + { + if (clock_getres(CLOCK_MONOTONIC, res)) + UTIL_DISPLAYLEVEL(1, "ERROR: Failed to init clock\n"); + } + UTIL_STATIC void UTIL_getTime(UTIL_time_t* time) + { + if (clock_gettime(CLOCK_MONOTONIC, time)) + UTIL_DISPLAYLEVEL(1, "ERROR: Failed to get time\n"); + } + UTIL_STATIC UTIL_time_t UTIL_getSpanTime(UTIL_freq_t res, UTIL_time_t begin, UTIL_time_t end) + { + UTIL_time_t diff; + (void)res; + if (end.tv_nsec < begin.tv_nsec) { + diff.tv_sec = (end.tv_sec - 1) - begin.tv_sec; + diff.tv_nsec = (end.tv_nsec + 1000000000ULL) - begin.tv_nsec; + } else { + diff.tv_sec = end.tv_sec - begin.tv_sec; + diff.tv_nsec = end.tv_nsec - begin.tv_nsec; + } + return diff; + } + UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t res, UTIL_time_t begin, UTIL_time_t end) + { + UTIL_time_t const diff = UTIL_getSpanTime(res, begin, end); + U64 micro = 0; + micro += 1000000ULL * diff.tv_sec; + micro += diff.tv_nsec / 1000ULL; + return micro; + } + UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t res, UTIL_time_t begin, UTIL_time_t end) + { + UTIL_time_t const diff = UTIL_getSpanTime(res, begin, end); + U64 nano = 0; + nano += 1000000000ULL * diff.tv_sec; + nano += diff.tv_nsec; + return nano; + } #else /* relies on standard C (note : clock_t measurements can be wrong when using multi-threading) */ - typedef clock_t UTIL_freq_t; - typedef clock_t UTIL_time_t; - UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { *ticksPerSecond=0; } - UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { *x = clock(); } - UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { (void)ticksPerSecond; return 1000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } - UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { (void)ticksPerSecond; return 1000000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } + typedef clock_t UTIL_freq_t; + typedef clock_t UTIL_time_t; + UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { *ticksPerSecond=0; } + UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { *x = clock(); } + UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { (void)ticksPerSecond; return 1000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } + UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { (void)ticksPerSecond; return 1000000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } #endif From e89065506e75cebcc50f65c48d27b8eb31a87fbc Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Tue, 12 Sep 2017 14:29:39 -0700 Subject: [PATCH 125/248] Make decodecorpus generate raw compressed blocks --- tests/decodecorpus.c | 273 +++++++++++++++++++++++++++++++++---------- 1 file changed, 214 insertions(+), 59 deletions(-) diff --git a/tests/decodecorpus.c b/tests/decodecorpus.c index a06571328..fef62aa61 100644 --- a/tests/decodecorpus.c +++ b/tests/decodecorpus.c @@ -238,6 +238,11 @@ typedef struct { size_t dictContentSize; BYTE* dictContent; } dictInfo; + +typedef enum { + gt_frame = 0, /* generate frames */ + gt_block, /* generate compressed blocks without block/frame headers */ +} genType_e; /*-******************************************************* * Generator Functions *********************************************************/ @@ -453,7 +458,7 @@ static size_t writeHufHeader(U32* seed, HUF_CElt* hufTable, void* dst, size_t ds return op - ostart; } -/* Write a Huffman coded literals block and return the litearls size */ +/* Write a Huffman coded literals block and return the literals size */ static size_t writeLiteralsBlockCompressed(U32* seed, frame_t* frame, size_t contentSize) { BYTE* origop = (BYTE*)frame->data; @@ -1165,6 +1170,61 @@ static void initFrame(frame_t* fr) fr->stats.rep[2] = 8; } +/** + * Generated a single zstd compressed block with no block/frame header. + * Returns the final seed. + */ +static U32 generateCompressedBlock(U32 seed, frame_t* frame, dictInfo info) +{ + size_t blockContentSize; + int blockWritten = 0; + BYTE* op; + DISPLAYLEVEL(1, "block seed: %u\n", seed); + initFrame(frame); + op = (BYTE*)frame->data; + + while (!blockWritten) { + size_t cSize; + /* generate window size */ + { + int const exponent = RAND(&seed) % (MAX_WINDOW_LOG - 10); + int const mantissa = RAND(&seed) % 8; + frame->header.windowSize = (1U << (exponent + 10)); + frame->header.windowSize += (frame->header.windowSize / 8) * mantissa; + } + + /* generate content size */ + { + size_t const maxBlockSize = MIN(MAX_BLOCK_SIZE, frame->header.windowSize); + if (RAND(&seed) & 15) { + /* some full size blocks */ + blockContentSize = maxBlockSize; + } else if (RAND(&seed) & 7) { + /* some small blocks <= 128 bytes*/ + blockContentSize = RAND(&seed) % (1U << 7); + } else { + /* some variable size blocks */ + blockContentSize = RAND(&seed) % maxBlockSize; + } + } + + /* try generating a compressed block */ + frame->oldStats = frame->stats; + frame->data = op; + cSize = writeCompressedBlock(&seed, frame, blockContentSize, info); + if (cSize > blockContentSize) { + /* data doesn't compress -- try again */ + frame->stats = frame->oldStats; /* don't update the stats */ + DISPLAYLEVEL(3, " can't compress block\n"); + } else { + blockWritten = 1; + DISPLAYLEVEL(3, " block size: %u\n", (U32)cSize); + frame->src = (BYTE*)frame->src + blockContentSize; + } + } + return seed; +} + /* Return the final seed */ static U32 generateFrame(U32 seed, frame_t* fr, dictInfo info) { @@ -1323,7 +1383,7 @@ cleanup: return ret; } -static size_t testDecodeWithDict(U32 seed) +static size_t testDecodeWithDict(U32 seed, genType_e genType) { /* create variables */ size_t const dictSize = RAND(&seed) % (10 << 20) + ZDICT_DICTSIZE_MIN + ZDICT_CONTENTSIZE_MIN; @@ -1346,34 +1406,47 @@ static size_t testDecodeWithDict(U32 seed) { frame_t fr; + dictInfo info; + ZSTD_DCtx* const dctx = ZSTD_createDCtx(); + size_t ret; - /* generate frame */ + /* get dict info */ { size_t const headerSize = MAX(dictSize/4, 256); size_t const dictContentSize = dictSize-headerSize; BYTE* const dictContent = fullDict+headerSize; - dictInfo const info = initDictInfo(1, dictContentSize, dictContent, dictID); - seed = generateFrame(seed, &fr, info); + info = initDictInfo(1, dictContentSize, dictContent, dictID); } /* manually decompress and check difference */ - { - ZSTD_DCtx* const dctx = ZSTD_createDCtx(); - { - size_t const returnValue = ZSTD_decompress_usingDict(dctx, DECOMPRESSED_BUFFER, MAX_DECOMPRESSED_SIZE, - fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart, - fullDict, dictSize); - if (ZSTD_isError(returnValue)) { - errorDetected = returnValue; - goto dictTestCleanup; - } - } - - if (memcmp(DECOMPRESSED_BUFFER, fr.srcStart, (BYTE*)fr.src - (BYTE*)fr.srcStart) != 0) { - errorDetected = ERROR(corruption_detected); + if (genType == gt_frame) { + /* Test frame */ + seed = generateFrame(seed, &fr, info); + ret = ZSTD_decompress_usingDict(dctx, DECOMPRESSED_BUFFER, MAX_DECOMPRESSED_SIZE, + fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart, + fullDict, dictSize); + } else { + /* Test block */ + seed = generateCompressedBlock(seed, &fr, info); + ret = ZSTD_decompressBegin_usingDict(dctx, fullDict, dictSize); + if (ZSTD_isError(ret)) { + errorDetected = ret; + ZSTD_freeDCtx(dctx); goto dictTestCleanup; } - ZSTD_freeDCtx(dctx); + ret = ZSTD_decompressBlock(dctx, DECOMPRESSED_BUFFER, MAX_DECOMPRESSED_SIZE, + fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart); + } + ZSTD_freeDCtx(dctx); + + if (ZSTD_isError(ret)) { + errorDetected = ret; + goto dictTestCleanup; + } + + if (memcmp(DECOMPRESSED_BUFFER, fr.srcStart, (BYTE*)fr.src - (BYTE*)fr.srcStart) != 0) { + errorDetected = ERROR(corruption_detected); + goto dictTestCleanup; } } @@ -1382,7 +1455,91 @@ dictTestCleanup: return errorDetected; } -static int runTestMode(U32 seed, unsigned numFiles, unsigned const testDurationS) +static size_t testDecodeRawBlock(frame_t* fr) +{ + ZSTD_DCtx* dctx = ZSTD_createDCtx(); + size_t ret = ZSTD_decompressBegin(dctx); + if (ZSTD_isError(ret)) return ret; + + ret = ZSTD_decompressBlock( + dctx, + DECOMPRESSED_BUFFER, MAX_DECOMPRESSED_SIZE, + fr->dataStart, (BYTE*)fr->data - (BYTE*)fr->dataStart); + ZSTD_freeDCtx(dctx); + if (ZSTD_isError(ret)) return ret; + + if (memcmp(DECOMPRESSED_BUFFER, fr->srcStart, + (BYTE*)fr->src - (BYTE*)fr->srcStart) != 0) { + return ERROR(corruption_detected); + } + + return ret; +} + +static int runBlockTest(U32* seed) +{ + frame_t fr; + U32 const seedCopy = *seed; + { + dictInfo const info = initDictInfo(0, 0, NULL, 0); + *seed = generateCompressedBlock(*seed, &fr, info); + } + + { size_t const r = testDecodeRawBlock(&fr); + if (ZSTD_isError(r)) { + DISPLAY("Error in block mode on test seed %u: %s\n", seedCopy, + ZSTD_getErrorName(r)); + return 1; + } + } + + { + size_t const r = testDecodeWithDict(*seed, gt_block); + if (ZSTD_isError(r)) { + DISPLAY("Error in block mode with dictionary on test seed %u: %s\n", + seedCopy, ZSTD_getErrorName(r)); + return 1; + } + } + return 0; +} + +static int runFrameTest(U32* seed) +{ + frame_t fr; + U32 const seedCopy = *seed; + { + dictInfo const info = initDictInfo(0, 0, NULL, 0); + *seed = generateFrame(*seed, &fr, info); + } + + { size_t const r = testDecodeSimple(&fr); + if (ZSTD_isError(r)) { + DISPLAY("Error in simple mode on test seed %u: %s\n", seedCopy, + ZSTD_getErrorName(r)); + return 1; + } + } + { size_t const r = testDecodeStreaming(&fr); + if (ZSTD_isError(r)) { + DISPLAY("Error in streaming mode on test seed %u: %s\n", seedCopy, + ZSTD_getErrorName(r)); + return 1; + } + } + { + /* don't create a dictionary that is too big */ + size_t const r = testDecodeWithDict(*seed, gt_frame); + if (ZSTD_isError(r)) { + DISPLAY("Error in dictionary mode on test seed %u: %s\n", seedCopy, ZSTD_getErrorName(r)); + return 1; + } + } + return 0; +} + +static int runTestMode(U32 seed, unsigned numFiles, unsigned const testDurationS, + genType_e genType) { unsigned fnum; @@ -1394,39 +1551,21 @@ static int runTestMode(U32 seed, unsigned numFiles, unsigned const testDurationS DISPLAY("seed: %u\n", seed); for (fnum = 0; fnum < numFiles || clockSpan(startClock) < maxClockSpan; fnum++) { - frame_t fr; - U32 const seedCopy = seed; if (fnum < numFiles) DISPLAYUPDATE("\r%u/%u ", fnum, numFiles); else DISPLAYUPDATE("\r%u ", fnum); - { - dictInfo const info = initDictInfo(0, 0, NULL, 0); - seed = generateFrame(seed, &fr, info); - } + int ret; + if (genType == gt_frame) { + ret = runFrameTest(&seed); + } else { + ret = runBlockTest(&seed); + } - { size_t const r = testDecodeSimple(&fr); - if (ZSTD_isError(r)) { - DISPLAY("Error in simple mode on test seed %u: %s\n", seedCopy, - ZSTD_getErrorName(r)); - return 1; - } - } - { size_t const r = testDecodeStreaming(&fr); - if (ZSTD_isError(r)) { - DISPLAY("Error in streaming mode on test seed %u: %s\n", seedCopy, - ZSTD_getErrorName(r)); - return 1; - } - } - { - /* don't create a dictionary that is too big */ - size_t const r = testDecodeWithDict(seed); - if (ZSTD_isError(r)) { - DISPLAY("Error in dictionary mode on test seed %u: %s\n", seedCopy, ZSTD_getErrorName(r)); - return 1; - } + if (ret) { + return ret; + } } } @@ -1441,7 +1580,7 @@ static int runTestMode(U32 seed, unsigned numFiles, unsigned const testDurationS *********************************************************/ static int generateFile(U32 seed, const char* const path, - const char* const origPath) + const char* const origPath, genType_e genType) { frame_t fr; @@ -1449,9 +1588,12 @@ static int generateFile(U32 seed, const char* const path, { dictInfo const info = initDictInfo(0, 0, NULL, 0); - generateFrame(seed, &fr, info); + if (genType == gt_frame) { + generateFrame(seed, &fr, info); + } else { + generateCompressedBlock(seed, &fr, info); + } } - outputBuffer(fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart, path); if (origPath) { outputBuffer(fr.srcStart, (BYTE*)fr.src - (BYTE*)fr.srcStart, origPath); @@ -1460,7 +1602,7 @@ static int generateFile(U32 seed, const char* const path, } static int generateCorpus(U32 seed, unsigned numFiles, const char* const path, - const char* const origPath) + const char* const origPath, genType_e genType) { char outPath[MAX_PATH]; unsigned fnum; @@ -1474,7 +1616,11 @@ static int generateCorpus(U32 seed, unsigned numFiles, const char* const path, { dictInfo const info = initDictInfo(0, 0, NULL, 0); - seed = generateFrame(seed, &fr, info); + if (genType == gt_frame) { + seed = generateFrame(seed, &fr, info); + } else { + seed = generateCompressedBlock(seed, &fr, info); + } } if (snprintf(outPath, MAX_PATH, "%s/z%06u.zst", path, fnum) + 1 > MAX_PATH) { @@ -1498,7 +1644,8 @@ static int generateCorpus(U32 seed, unsigned numFiles, const char* const path, } static int generateCorpusWithDict(U32 seed, unsigned numFiles, const char* const path, - const char* const origPath, const size_t dictSize) + const char* const origPath, const size_t dictSize, + genType_e genType) { char outPath[MAX_PATH]; BYTE* fullDict; @@ -1550,7 +1697,11 @@ static int generateCorpusWithDict(U32 seed, unsigned numFiles, const char* const size_t const dictContentSize = dictSize-headerSize; BYTE* const dictContent = fullDict+headerSize; dictInfo const info = initDictInfo(1, dictContentSize, dictContent, dictID); - seed = generateFrame(seed, &fr, info); + if (genType == gt_frame) { + seed = generateFrame(seed, &fr, info); + } else { + seed = generateCompressedBlock(seed, &fr, info); + } } if (numFiles != 0) { @@ -1630,6 +1781,7 @@ static void advancedUsage(const char* programName) DISPLAY( "Advanced arguments :\n"); DISPLAY( " --content-size : always include the content size in the frame header\n"); DISPLAY( " --use-dict=# : include a dictionary used to decompress the corpus\n"); + DISPLAY( " --gen-blocks : generate raw compressed blocks without block/frame headers\n"); } /*! readU32FromChar() : @@ -1676,6 +1828,7 @@ int main(int argc, char** argv) const char* origPath = NULL; int useDict = 0; unsigned dictSize = (10 << 10); /* 10 kB default */ + genType_e genType = gt_frame; int argNb; @@ -1739,6 +1892,8 @@ int main(int argc, char** argv) } else if (longCommandWArg(&argument, "use-dict=")) { dictSize = readU32FromChar(&argument); useDict = 1; + } else if (strcmp(argument, "gen-blocks") == 0) { + genType = gt_block; } else { advancedUsage(argv[0]); return 1; @@ -1755,7 +1910,7 @@ int main(int argc, char** argv) } if (testMode) { - return runTestMode(seed, numFiles, testDuration); + return runTestMode(seed, numFiles, testDuration, genType); } else { if (testDuration) { DISPLAY("Error: -T requires test mode (-t)\n\n"); @@ -1771,12 +1926,12 @@ int main(int argc, char** argv) } if (numFiles == 0 && useDict == 0) { - return generateFile(seed, path, origPath); + return generateFile(seed, path, origPath, genType); } else if (useDict == 0){ - return generateCorpus(seed, numFiles, path, origPath); + return generateCorpus(seed, numFiles, path, origPath, genType); } else { /* should generate files with a dictionary */ - return generateCorpusWithDict(seed, numFiles, path, origPath, dictSize); + return generateCorpusWithDict(seed, numFiles, path, origPath, dictSize, genType); } } From c95c0c9725e173d9f8cbc3532e39f49bbc034f63 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 12 Sep 2017 18:12:46 -0700 Subject: [PATCH 126/248] modified util::time API for easier invocation. - no longer expose frequency timer : it's either useless, or stored internally in a static variable (init is only necessary once). - UTIL_getTime() provides result by function return. --- programs/bench.c | 25 ++++---- programs/util.h | 99 +++++++++++++++++++------------ tests/fullbench.c | 10 ++-- zlibWrapper/examples/zwrapbench.c | 36 ++++++----- 4 files changed, 93 insertions(+), 77 deletions(-) diff --git a/programs/bench.c b/programs/bench.c index a691f7313..11f778d0d 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -171,7 +171,6 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, size_t cSize = 0; double ratio = 0.; U32 nbBlocks; - UTIL_freq_t ticksPerSecond; /* checks */ if (!compressedBuffer || !resultBuffer || !blockTable || !ctx || !dctx) @@ -179,7 +178,6 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, /* init */ if (strlen(displayName)>17) displayName += strlen(displayName)-17; /* display last 17 characters */ - UTIL_initTimer(&ticksPerSecond); if (g_decodeOnly) { /* benchmark only decompression : source must be already compressed */ const char* srcPtr = (const char*)srcBuffer; @@ -239,15 +237,15 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, const char* const marks[NB_MARKS] = { " |", " /", " =", "\\" }; U32 markNb = 0; - UTIL_getTime(&coolTime); + coolTime = UTIL_getTime(); DISPLAYLEVEL(2, "\r%79s\r", ""); while (!cCompleted || !dCompleted) { /* overheat protection */ - if (UTIL_clockSpanMicro(coolTime, ticksPerSecond) > ACTIVEPERIOD_MICROSEC) { + if (UTIL_clockSpanMicro(coolTime) > ACTIVEPERIOD_MICROSEC) { DISPLAYLEVEL(2, "\rcooling down ... \r"); UTIL_sleep(COOLPERIOD_SEC); - UTIL_getTime(&coolTime); + coolTime = UTIL_getTime(); } if (!g_decodeOnly) { @@ -257,8 +255,8 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, if (!cCompleted) memset(compressedBuffer, 0xE5, maxCompressedSize); /* warm up and erase result buffer */ UTIL_sleepMilli(1); /* give processor time to other processes */ - UTIL_waitForNextTick(ticksPerSecond); - UTIL_getTime(&clockStart); + UTIL_waitForNextTick(); + clockStart = UTIL_getTime(); if (!cCompleted) { /* still some time to do compression tests */ U64 const clockLoop = g_nbSeconds ? TIMELOOP_MICROSEC : 1; @@ -330,9 +328,9 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, blockTable[blockNb].cSize = rSize; } nbLoops++; - } while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop); + } while (UTIL_clockSpanMicro(clockStart) < clockLoop); ZSTD_freeCDict(cdict); - { U64 const clockSpanMicro = UTIL_clockSpanMicro(clockStart, ticksPerSecond); + { U64 const clockSpanMicro = UTIL_clockSpanMicro(clockStart); if (clockSpanMicro < fastestC*nbLoops) fastestC = clockSpanMicro / nbLoops; totalCTime += clockSpanMicro; cCompleted = (totalCTime >= maxTime); @@ -357,15 +355,14 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, if (!dCompleted) memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */ UTIL_sleepMilli(1); /* give processor time to other processes */ - UTIL_waitForNextTick(ticksPerSecond); + UTIL_waitForNextTick(); if (!dCompleted) { U64 clockLoop = g_nbSeconds ? TIMELOOP_MICROSEC : 1; U32 nbLoops = 0; - UTIL_time_t clockStart; ZSTD_DDict* const ddict = ZSTD_createDDict(dictBuffer, dictBufferSize); + UTIL_time_t const clockStart = UTIL_getTime(); if (!ddict) EXM_THROW(2, "ZSTD_createDDict() allocation failure"); - UTIL_getTime(&clockStart); do { U32 blockNb; for (blockNb=0; blockNb= maxTime); diff --git a/programs/util.h b/programs/util.h index 3903db5d8..d66e6bd3f 100644 --- a/programs/util.h +++ b/programs/util.h @@ -118,38 +118,64 @@ static int g_utilDisplayLevel; * Time functions ******************************************/ #if defined(_WIN32) /* Windows */ - typedef LARGE_INTEGER UTIL_freq_t; typedef LARGE_INTEGER UTIL_time_t; - UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { if (!QueryPerformanceFrequency(ticksPerSecond)) UTIL_DISPLAYLEVEL(1, "ERROR: QueryPerformance not present\n"); } - UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { QueryPerformanceCounter(x); } - UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; } - UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; } + UTIL_STATIC UTIL_time_t UTIL_getTime(void) { UTIL_time_t x; QueryPerformanceCounter(&x); return x; } + UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) + { + static LARGE_INTEGER ticksPerSecond = 0; + if (!ticksPerSecond) { + if (!QueryPerformanceFrequency(&ticksPerSecond)) + UTIL_DISPLAYLEVEL(1, "ERROR: QueryPerformanceFrequency() failure\n"); + } + return 1000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; + } + UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) + { + static LARGE_INTEGER ticksPerSecond = 0; + if (!ticksPerSecond) { + if (!QueryPerformanceFrequency(&ticksPerSecond)) + UTIL_DISPLAYLEVEL(1, "ERROR: QueryPerformanceFrequency() failure\n"); + } + return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; + } #elif defined(__APPLE__) && defined(__MACH__) #include - typedef mach_timebase_info_data_t UTIL_freq_t; typedef U64 UTIL_time_t; - UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* rate) { mach_timebase_info(rate); } - UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { *x = mach_absolute_time(); } - UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t rate, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return (((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom))/1000ULL; } - UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t rate, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return ((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom); } + UTIL_STATIC UTIL_time_t UTIL_getTime(void) { return mach_absolute_time(); } + UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) + { + static mach_timebase_info_data_t rate; + static int init = 0; + if (!init) { + mach_timebase_info(&rate); + init = 1; + } + return (((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom))/1000ULL; + } + UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) + { + static mach_timebase_info_data_t rate; + static int init = 0; + if (!init) { + mach_timebase_info(&rate); + init = 1; + } + return ((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom); + } #elif (PLATFORM_POSIX_VERSION >= 200112L) #include typedef struct timespec UTIL_freq_t; typedef struct timespec UTIL_time_t; - UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* res) + UTIL_STATIC UTIL_time_t UTIL_getTime(void) { - if (clock_getres(CLOCK_MONOTONIC, res)) - UTIL_DISPLAYLEVEL(1, "ERROR: Failed to init clock\n"); + UTIL_time_t time; + if (clock_gettime(CLOCK_MONOTONIC, &time)) + UTIL_DISPLAYLEVEL(1, "ERROR: Failed to get time\n"); /* we could also exit() */ + return time; } - UTIL_STATIC void UTIL_getTime(UTIL_time_t* time) - { - if (clock_gettime(CLOCK_MONOTONIC, time)) - UTIL_DISPLAYLEVEL(1, "ERROR: Failed to get time\n"); - } - UTIL_STATIC UTIL_time_t UTIL_getSpanTime(UTIL_freq_t res, UTIL_time_t begin, UTIL_time_t end) + UTIL_STATIC UTIL_time_t UTIL_getSpanTime(UTIL_time_t begin, UTIL_time_t end) { UTIL_time_t diff; - (void)res; if (end.tv_nsec < begin.tv_nsec) { diff.tv_sec = (end.tv_sec - 1) - begin.tv_sec; diff.tv_nsec = (end.tv_nsec + 1000000000ULL) - begin.tv_nsec; @@ -159,48 +185,45 @@ static int g_utilDisplayLevel; } return diff; } - UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t res, UTIL_time_t begin, UTIL_time_t end) + UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t begin, UTIL_time_t end) { - UTIL_time_t const diff = UTIL_getSpanTime(res, begin, end); + UTIL_time_t const diff = UTIL_getSpanTime(begin, end); U64 micro = 0; micro += 1000000ULL * diff.tv_sec; micro += diff.tv_nsec / 1000ULL; return micro; } - UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t res, UTIL_time_t begin, UTIL_time_t end) + UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t begin, UTIL_time_t end) { - UTIL_time_t const diff = UTIL_getSpanTime(res, begin, end); + UTIL_time_t const diff = UTIL_getSpanTime(begin, end); U64 nano = 0; nano += 1000000000ULL * diff.tv_sec; nano += diff.tv_nsec; return nano; } #else /* relies on standard C (note : clock_t measurements can be wrong when using multi-threading) */ - typedef clock_t UTIL_freq_t; typedef clock_t UTIL_time_t; - UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { *ticksPerSecond=0; } - UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { *x = clock(); } - UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { (void)ticksPerSecond; return 1000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } - UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { (void)ticksPerSecond; return 1000000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } + UTIL_STATIC UTIL_time_t UTIL_getTime(void) { return clock(); } + UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } + UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } #endif /* returns time span in microseconds */ -UTIL_STATIC U64 UTIL_clockSpanMicro( UTIL_time_t clockStart, UTIL_freq_t ticksPerSecond ) +UTIL_STATIC U64 UTIL_clockSpanMicro( UTIL_time_t clockStart ) { - UTIL_time_t clockEnd; - UTIL_getTime(&clockEnd); - return UTIL_getSpanTimeMicro(ticksPerSecond, clockStart, clockEnd); + UTIL_time_t const clockEnd = UTIL_getTime(); + return UTIL_getSpanTimeMicro(clockStart, clockEnd); } -UTIL_STATIC void UTIL_waitForNextTick(UTIL_freq_t ticksPerSecond) +UTIL_STATIC void UTIL_waitForNextTick() { - UTIL_time_t clockStart, clockEnd; - UTIL_getTime(&clockStart); + UTIL_time_t const clockStart = UTIL_getTime(); + UTIL_time_t clockEnd; do { - UTIL_getTime(&clockEnd); - } while (UTIL_getSpanTimeNano(ticksPerSecond, clockStart, clockEnd) == 0); + clockEnd = UTIL_getTime(); + } while (UTIL_getSpanTimeNano(clockStart, clockEnd) == 0); } diff --git a/tests/fullbench.c b/tests/fullbench.c index 2361debf8..bd9dc6135 100644 --- a/tests/fullbench.c +++ b/tests/fullbench.c @@ -422,8 +422,6 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) { U32 loopNb; # define TIME_SEC_MICROSEC (1*1000000ULL) /* 1 second */ U64 const clockLoop = TIMELOOP_S * TIME_SEC_MICROSEC; - UTIL_freq_t ticksPerSecond; - UTIL_initTimer(&ticksPerSecond); DISPLAY("%2i- %-30.30s : \r", benchNb, benchName); for (loopNb = 1; loopNb <= g_nbIterations; loopNb++) { UTIL_time_t clockStart; @@ -431,13 +429,13 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) U32 nbRounds; UTIL_sleepMilli(1); /* give processor time to other processes */ - UTIL_waitForNextTick(ticksPerSecond); - UTIL_getTime(&clockStart); - for (nbRounds=0; UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop; nbRounds++) { + UTIL_waitForNextTick(); + clockStart = UTIL_getTime(); + for (nbRounds=0; UTIL_clockSpanMicro(clockStart) < clockLoop; nbRounds++) { benchResult = benchFunction(dstBuff, dstBuffSize, buff2, src, srcSize); if (ZSTD_isError(benchResult)) { DISPLAY("ERROR ! %s() => %s !! \n", benchName, ZSTD_getErrorName(benchResult)); exit(1); } } - { U64 const clockSpanMicro = UTIL_clockSpanMicro(clockStart, ticksPerSecond); + { U64 const clockSpanMicro = UTIL_clockSpanMicro(clockStart); double const averageTime = (double)clockSpanMicro / TIME_SEC_MICROSEC / nbRounds; if (averageTime < bestTime) bestTime = averageTime; DISPLAY("%2i- %-30.30s : %7.1f MB/s (%9u)\r", loopNb, benchName, (double)srcSize / (1 MB) / bestTime, (U32)benchResult); diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index f0ed5fe17..25a23f885 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -161,7 +161,6 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize, ZSTD_CCtx* const ctx = ZSTD_createCCtx(); ZSTD_DCtx* const dctx = ZSTD_createDCtx(); U32 nbBlocks; - UTIL_freq_t ticksPerSecond; /* checks */ if (!compressedBuffer || !resultBuffer || !blockTable || !ctx || !dctx) @@ -169,7 +168,6 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize, /* init */ if (strlen(displayName)>17) displayName += strlen(displayName)-17; /* can only display 17 characters */ - UTIL_initTimer(&ticksPerSecond); /* Init blockTable data */ { z_const char* srcPtr = (z_const char*)srcBuffer; @@ -209,17 +207,17 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize, size_t cSize = 0; double ratio = 0.; - UTIL_getTime(&coolTime); + coolTime = UTIL_getTime(); DISPLAYLEVEL(2, "\r%79s\r", ""); while (!cCompleted | !dCompleted) { UTIL_time_t clockStart; U64 clockLoop = g_nbIterations ? TIMELOOP_MICROSEC : 1; /* overheat protection */ - if (UTIL_clockSpanMicro(coolTime, ticksPerSecond) > ACTIVEPERIOD_MICROSEC) { + if (UTIL_clockSpanMicro(coolTime) > ACTIVEPERIOD_MICROSEC) { DISPLAYLEVEL(2, "\rcooling down ... \r"); UTIL_sleep(COOLPERIOD_SEC); - UTIL_getTime(&coolTime); + coolTime = UTIL_getTime(); } /* Compression */ @@ -227,8 +225,8 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize, if (!cCompleted) memset(compressedBuffer, 0xE5, maxCompressedSize); /* warm up and erase result buffer */ UTIL_sleepMilli(1); /* give processor time to other processes */ - UTIL_waitForNextTick(ticksPerSecond); - UTIL_getTime(&clockStart); + UTIL_waitForNextTick(); + clockStart = UTIL_getTime(); if (!cCompleted) { /* still some time to do compression tests */ U32 nbLoops = 0; @@ -256,7 +254,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize, blockTable[blockNb].cSize = rSize; } nbLoops++; - } while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop); + } while (UTIL_clockSpanMicro(clockStart) < clockLoop); ZSTD_freeCDict(cdict); } else if (compressor == BMK_ZSTD_STREAM) { ZSTD_parameters const zparams = ZSTD_getParams(cLevel, avgSize, dictBufferSize); @@ -285,7 +283,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize, blockTable[blockNb].cSize = outBuffer.pos; } nbLoops++; - } while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop); + } while (UTIL_clockSpanMicro(clockStart) < clockLoop); ZSTD_freeCStream(zbc); } else if (compressor == BMK_ZWRAP_ZLIB_REUSE || compressor == BMK_ZWRAP_ZSTD_REUSE || compressor == BMK_ZLIB_REUSE) { z_stream def; @@ -326,7 +324,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize, blockTable[blockNb].cSize = def.total_out; } nbLoops++; - } while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop); + } while (UTIL_clockSpanMicro(clockStart) < clockLoop); ret = deflateEnd(&def); if (ret != Z_OK) EXM_THROW(1, "deflateEnd failure"); } else { @@ -359,9 +357,9 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize, blockTable[blockNb].cSize = def.total_out; } nbLoops++; - } while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop); + } while (UTIL_clockSpanMicro(clockStart) < clockLoop); } - { U64 const clockSpan = UTIL_clockSpanMicro(clockStart, ticksPerSecond); + { U64 const clockSpan = UTIL_clockSpanMicro(clockStart); if (clockSpan < fastestC*nbLoops) fastestC = clockSpan / nbLoops; totalCTime += clockSpan; cCompleted = totalCTime>maxTime; @@ -381,8 +379,8 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize, if (!dCompleted) memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */ UTIL_sleepMilli(1); /* give processor time to other processes */ - UTIL_waitForNextTick(ticksPerSecond); - UTIL_getTime(&clockStart); + UTIL_waitForNextTick(); + clockStart = UTIL_getTime(); if (!dCompleted) { U32 nbLoops = 0; @@ -405,7 +403,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize, blockTable[blockNb].resSize = regenSize; } nbLoops++; - } while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop); + } while (UTIL_clockSpanMicro(clockStart) < clockLoop); ZSTD_freeDDict(ddict); } else if (compressor == BMK_ZSTD_STREAM) { ZSTD_inBuffer inBuffer; @@ -431,7 +429,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize, blockTable[blockNb].resSize = outBuffer.pos; } nbLoops++; - } while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop); + } while (UTIL_clockSpanMicro(clockStart) < clockLoop); ZSTD_freeDStream(zbd); } else if (compressor == BMK_ZWRAP_ZLIB_REUSE || compressor == BMK_ZWRAP_ZSTD_REUSE || compressor == BMK_ZLIB_REUSE) { z_stream inf; @@ -467,7 +465,7 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize, blockTable[blockNb].resSize = inf.total_out; } nbLoops++; - } while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop); + } while (UTIL_clockSpanMicro(clockStart) < clockLoop); ret = inflateEnd(&inf); if (ret != Z_OK) EXM_THROW(1, "inflateEnd failure"); } else { @@ -501,9 +499,9 @@ static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize, blockTable[blockNb].resSize = inf.total_out; } nbLoops++; - } while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop); + } while (UTIL_clockSpanMicro(clockStart) < clockLoop); } - { U64 const clockSpan = UTIL_clockSpanMicro(clockStart, ticksPerSecond); + { U64 const clockSpan = UTIL_clockSpanMicro(clockStart); if (clockSpan < fastestD*nbLoops) fastestD = clockSpan / nbLoops; totalDTime += clockSpan; dCompleted = totalDTime>maxTime; From bc41c7f0eb36e911626e3414eb389234cec377db Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 12 Sep 2017 19:32:26 -0700 Subject: [PATCH 127/248] fixed minor prototype warning --- programs/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/util.h b/programs/util.h index d66e6bd3f..65eb195dc 100644 --- a/programs/util.h +++ b/programs/util.h @@ -217,7 +217,7 @@ UTIL_STATIC U64 UTIL_clockSpanMicro( UTIL_time_t clockStart ) } -UTIL_STATIC void UTIL_waitForNextTick() +UTIL_STATIC void UTIL_waitForNextTick(void) { UTIL_time_t const clockStart = UTIL_getTime(); UTIL_time_t clockEnd; From 8f26dc3f9c985d60a87d5bbfce20b15427575046 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 12 Sep 2017 21:21:17 -0700 Subject: [PATCH 128/248] blindfix for Visual LARGE_INTEGER is not an integer : https://msdn.microsoft.com/en-us/library/windows/desktop/aa383713(v=vs.85).aspx Do not take any risk with the structure definition : use int init = 0; like Mac code --- programs/util.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/programs/util.h b/programs/util.h index 65eb195dc..c8be5f5fb 100644 --- a/programs/util.h +++ b/programs/util.h @@ -122,19 +122,23 @@ static int g_utilDisplayLevel; UTIL_STATIC UTIL_time_t UTIL_getTime(void) { UTIL_time_t x; QueryPerformanceCounter(&x); return x; } UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) { - static LARGE_INTEGER ticksPerSecond = 0; - if (!ticksPerSecond) { + static LARGE_INTEGER ticksPerSecond; + static int init = 0; + if (!init) { if (!QueryPerformanceFrequency(&ticksPerSecond)) UTIL_DISPLAYLEVEL(1, "ERROR: QueryPerformanceFrequency() failure\n"); + init = 1; } return 1000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; } UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) { - static LARGE_INTEGER ticksPerSecond = 0; - if (!ticksPerSecond) { + static LARGE_INTEGER ticksPerSecond; + static int init = 0; + if (!init) { if (!QueryPerformanceFrequency(&ticksPerSecond)) UTIL_DISPLAYLEVEL(1, "ERROR: QueryPerformanceFrequency() failure\n"); + init = 1; } return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; } From 40bf0ced7d92e3cbaf167a7f8fbc3d6aa7f18460 Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Wed, 13 Sep 2017 15:07:03 -0700 Subject: [PATCH 129/248] Add flag to limit max decompressed size in decodeCorpus --- tests/decodecorpus.c | 46 +++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/tests/decodecorpus.c b/tests/decodecorpus.c index fef62aa61..a2e44950c 100644 --- a/tests/decodecorpus.c +++ b/tests/decodecorpus.c @@ -174,7 +174,8 @@ const char *BLOCK_TYPES[] = {"raw", "rle", "compressed"}; #define MAX_DECOMPRESSED_SIZE (1ULL << MAX_DECOMPRESSED_SIZE_LOG) #define MAX_WINDOW_LOG 22 /* Recommended support is 8MB, so limit to 4MB + mantissa */ -#define MAX_BLOCK_SIZE (128ULL * 1024) +#define MAX_BLOCK_SIZE_LOG 17 +#define MAX_BLOCK_SIZE (1ULL << MAX_BLOCK_SIZE_LOG) /* 128 KB */ #define MIN_SEQ_LEN (3) #define MAX_NB_SEQ ((MAX_BLOCK_SIZE + MIN_SEQ_LEN - 1) / MIN_SEQ_LEN) @@ -243,6 +244,13 @@ typedef enum { gt_frame = 0, /* generate frames */ gt_block, /* generate compressed blocks without block/frame headers */ } genType_e; + +/*-******************************************************* +* Global variables (set from command line) +*********************************************************/ +U32 g_maxDecompressedSizeLog = MAX_DECOMPRESSED_SIZE_LOG; /* <= 20 */ +U32 g_maxBlockSize = MAX_BLOCK_SIZE; /* <= 128 KB */ + /*-******************************************************* * Generator Functions *********************************************************/ @@ -279,12 +287,12 @@ static void writeFrameHeader(U32* seed, frame_t* frame, dictInfo info) { /* Generate random content size */ size_t highBit; - if (RAND(seed) & 7) { + if (RAND(seed) & 7 && g_maxDecompressedSizeLog > 7) { /* do content of at least 128 bytes */ - highBit = 1ULL << RAND_range(seed, 7, MAX_DECOMPRESSED_SIZE_LOG); + highBit = 1ULL << RAND_range(seed, 7, g_maxDecompressedSizeLog); } else if (RAND(seed) & 3) { /* do small content */ - highBit = 1ULL << RAND_range(seed, 0, 7); + highBit = 1ULL << RAND_range(seed, 0, MIN(7, 1ULL << g_maxDecompressedSizeLog)); } else { /* 0 size frame */ highBit = 0; @@ -364,7 +372,7 @@ static size_t writeLiteralsBlockSimple(U32* seed, frame_t* frame, size_t content int const type = RAND(seed) % 2; int const sizeFormatDesc = RAND(seed) % 8; size_t litSize; - size_t maxLitSize = MIN(contentSize, MAX_BLOCK_SIZE); + size_t maxLitSize = MIN(contentSize, g_maxBlockSize); if (sizeFormatDesc == 0) { /* Size_FormatDesc = ?0 */ @@ -469,7 +477,7 @@ static size_t writeLiteralsBlockCompressed(U32* seed, frame_t* frame, size_t con size_t litSize; size_t hufHeaderSize = 0; size_t compressedSize = 0; - size_t maxLitSize = MIN(contentSize-3, MAX_BLOCK_SIZE); + size_t maxLitSize = MIN(contentSize-3, g_maxBlockSize); symbolEncodingType_e hType; @@ -1086,7 +1094,7 @@ static void writeBlock(U32* seed, frame_t* frame, size_t contentSize, static void writeBlocks(U32* seed, frame_t* frame, dictInfo info) { size_t contentLeft = frame->header.contentSize; - size_t const maxBlockSize = MIN(MAX_BLOCK_SIZE, frame->header.windowSize); + size_t const maxBlockSize = MIN(g_maxBlockSize, frame->header.windowSize); while (1) { /* 1 in 4 chance of ending frame */ int const lastBlock = contentLeft > maxBlockSize ? 0 : !(RAND(seed) & 3); @@ -1195,11 +1203,11 @@ static U32 generateCompressedBlock(U32 seed, frame_t* frame, dictInfo info) /* generate content size */ { - size_t const maxBlockSize = MIN(MAX_BLOCK_SIZE, frame->header.windowSize); + size_t const maxBlockSize = MIN(g_maxBlockSize, frame->header.windowSize); if (RAND(&seed) & 15) { /* some full size blocks */ blockContentSize = maxBlockSize; - } else if (RAND(&seed) & 7) { + } else if (RAND(&seed) & 7 && g_maxBlockSize >= (1U << 7)) { /* some small blocks <= 128 bytes*/ blockContentSize = RAND(&seed) % (1U << 7); } else { @@ -1778,10 +1786,13 @@ static void advancedUsage(const char* programName) { usage(programName); DISPLAY( "\n"); - DISPLAY( "Advanced arguments :\n"); - DISPLAY( " --content-size : always include the content size in the frame header\n"); - DISPLAY( " --use-dict=# : include a dictionary used to decompress the corpus\n"); - DISPLAY( " --gen-blocks : generate raw compressed blocks without block/frame headers\n"); + DISPLAY( "Advanced arguments :\n"); + DISPLAY( " --content-size : always include the content size in the frame header\n"); + DISPLAY( " --use-dict=# : include a dictionary used to decompress the corpus\n"); + DISPLAY( " --gen-blocks : generate raw compressed blocks without block/frame headers\n"); + DISPLAY( " --max-block-size-log=# : max block size log, must be in range [2, 17]\n"); + DISPLAY( " --max-content-size-log=# : max content size log, must be <= 20\n"); + DISPLAY( " (this is ignored with gen-blocks)\n"); } /*! readU32FromChar() : @@ -1894,6 +1905,15 @@ int main(int argc, char** argv) useDict = 1; } else if (strcmp(argument, "gen-blocks") == 0) { genType = gt_block; + } else if (longCommandWArg(&argument, "max-block-size-log=")) { + U32 value = readU32FromChar(&argument); + if (value >= 2 && value <= MAX_BLOCK_SIZE) { + g_maxBlockSize = 1U << value; + } + } else if (longCommandWArg(&argument, "max-content-size-log=")) { + U32 value = readU32FromChar(&argument); + g_maxDecompressedSizeLog = + MIN(MAX_DECOMPRESSED_SIZE_LOG, value); } else { advancedUsage(argv[0]); return 1; From 963558a072c02a74adc7db2689dd50c90bdec22a Mon Sep 17 00:00:00 2001 From: Stella Lau Date: Wed, 13 Sep 2017 16:01:16 -0700 Subject: [PATCH 130/248] Fix implicit conversion error --- tests/decodecorpus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/decodecorpus.c b/tests/decodecorpus.c index a2e44950c..9cde2825e 100644 --- a/tests/decodecorpus.c +++ b/tests/decodecorpus.c @@ -292,7 +292,7 @@ static void writeFrameHeader(U32* seed, frame_t* frame, dictInfo info) highBit = 1ULL << RAND_range(seed, 7, g_maxDecompressedSizeLog); } else if (RAND(seed) & 3) { /* do small content */ - highBit = 1ULL << RAND_range(seed, 0, MIN(7, 1ULL << g_maxDecompressedSizeLog)); + highBit = 1ULL << RAND_range(seed, 0, MIN(7, 1U << g_maxDecompressedSizeLog)); } else { /* 0 size frame */ highBit = 0; From 677c2cbf8959b7c71b69208c35268cbe7a809773 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 12 Sep 2017 20:20:27 -0700 Subject: [PATCH 131/248] Update fuzzer sources --- tests/fuzz/fuzz.h | 18 ++++++++++++++---- tests/fuzz/fuzz_helpers.h | 18 ++++++++++++++---- tests/fuzz/simple_decompress.c | 7 +++++-- tests/fuzz/simple_round_trip.c | 7 ++++--- tests/fuzz/stream_decompress.c | 4 ++-- tests/fuzz/stream_round_trip.c | 7 ++++--- 6 files changed, 43 insertions(+), 18 deletions(-) diff --git a/tests/fuzz/fuzz.h b/tests/fuzz/fuzz.h index 3017db3aa..a64845473 100644 --- a/tests/fuzz/fuzz.h +++ b/tests/fuzz/fuzz.h @@ -12,15 +12,17 @@ * Fuzz targets have some common parameters passed as macros during compilation. * Check the documentation for each individual fuzzer for more parameters. * - * @param STATEFULL_FUZZING: + * @param STATEFUL_FUZZING: * Define this to reuse state between fuzzer runs. This can be useful to * test code paths which are only executed when contexts are reused. * WARNING: Makes reproducing crashes much harder. * Default: Not defined. * @param FUZZ_RNG_SEED_SIZE: * The number of bytes of the source to look at when constructing a seed - * for the deterministic RNG. - * Default: 128. + * for the deterministic RNG. These bytes are discarded before passing + * the data to zstd functions. Every fuzzer initializes the RNG exactly + * once before doing anything else, even if it is unused. + * Default: 4. * @param ZSTD_DEBUG: * This is a parameter for the zstd library. Defining `ZSTD_DEBUG=1` * enables assert() statements in the zstd library. Higher levels enable @@ -41,12 +43,20 @@ #define FUZZ_H #ifndef FUZZ_RNG_SEED_SIZE -# define FUZZ_RNG_SEED_SIZE 128 +# define FUZZ_RNG_SEED_SIZE 4 #endif #include #include +#ifdef __cplusplus +extern "C" { +#endif + int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size); +#ifdef __cplusplus +} +#endif + #endif diff --git a/tests/fuzz/fuzz_helpers.h b/tests/fuzz/fuzz_helpers.h index f7cc3d5bb..d93881c80 100644 --- a/tests/fuzz/fuzz_helpers.h +++ b/tests/fuzz/fuzz_helpers.h @@ -19,6 +19,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) @@ -48,11 +52,13 @@ /** * Determininistically constructs a seed based on the fuzz input. - * Only looks at the first FUZZ_RNG_SEED_SIZE bytes of the input. + * Consumes up to the first FUZZ_RNG_SEED_SIZE bytes of the input. */ -FUZZ_STATIC uint32_t FUZZ_seed(const uint8_t *src, size_t size) { - size_t const toHash = MIN(FUZZ_RNG_SEED_SIZE, size); - return XXH32(src, toHash, 0); +FUZZ_STATIC uint32_t FUZZ_seed(uint8_t const **src, size_t* size) { + size_t const toHash = MIN(FUZZ_RNG_SEED_SIZE, *size); + return XXH32(*src, toHash, 0); + *size -= toHash; + *src += toHash; } #define FUZZ_rotl32(x, r) (((x) << (r)) | ((x) >> (32 - (r)))) @@ -67,4 +73,8 @@ FUZZ_STATIC uint32_t FUZZ_rand(uint32_t *state) { return rand32 >> 5; } +#ifdef __cplusplus +} +#endif + #endif diff --git a/tests/fuzz/simple_decompress.c b/tests/fuzz/simple_decompress.c index a225b9dc7..bba272c62 100644 --- a/tests/fuzz/simple_decompress.c +++ b/tests/fuzz/simple_decompress.c @@ -24,7 +24,10 @@ static size_t bufSize = 0; int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) { - size_t const neededBufSize = MAX(20 * size, (size_t)256 << 10); + size_t neededBufSize; + + FUZZ_seed(&src, &size); + neededBufSize = MAX(20 * size, (size_t)256 << 10); /* Allocate all buffers and contexts if not already allocated */ if (neededBufSize > bufSize) { @@ -39,7 +42,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) } ZSTD_decompressDCtx(dctx, rBuf, neededBufSize, src, size); -#ifndef STATEFULL_FUZZING +#ifndef STATEFUL_FUZZING ZSTD_freeDCtx(dctx); dctx = NULL; #endif return 0; diff --git a/tests/fuzz/simple_round_trip.c b/tests/fuzz/simple_round_trip.c index 63472bb44..9df025283 100644 --- a/tests/fuzz/simple_round_trip.c +++ b/tests/fuzz/simple_round_trip.c @@ -44,9 +44,10 @@ static size_t roundTripTest(void *result, size_t resultCapacity, int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) { - size_t const neededBufSize = ZSTD_compressBound(size); + size_t neededBufSize; - seed = FUZZ_seed(src, size); + seed = FUZZ_seed(&src, &size); + neededBufSize = ZSTD_compressBound(size); /* Allocate all buffers and contexts if not already allocated */ if (neededBufSize > bufSize) { @@ -73,7 +74,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size"); FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!"); } -#ifndef STATEFULL_FUZZING +#ifndef STATEFUL_FUZZING ZSTD_freeCCtx(cctx); cctx = NULL; ZSTD_freeDCtx(dctx); dctx = NULL; #endif diff --git a/tests/fuzz/stream_decompress.c b/tests/fuzz/stream_decompress.c index dfd746972..7ad571221 100644 --- a/tests/fuzz/stream_decompress.c +++ b/tests/fuzz/stream_decompress.c @@ -51,7 +51,7 @@ static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size) int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) { - seed = FUZZ_seed(src, size); + seed = FUZZ_seed(&src, &size); /* Allocate all buffers and contexts if not already allocated */ if (!buf) { @@ -78,7 +78,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) } error: -#ifndef STATEFULL_FUZZING +#ifndef STATEFUL_FUZZING ZSTD_freeDStream(dstream); dstream = NULL; #endif return 0; diff --git a/tests/fuzz/stream_round_trip.c b/tests/fuzz/stream_round_trip.c index 74adbeaba..e796c1e7f 100644 --- a/tests/fuzz/stream_round_trip.c +++ b/tests/fuzz/stream_round_trip.c @@ -114,9 +114,10 @@ static size_t compress(uint8_t *dst, size_t capacity, int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) { - size_t const neededBufSize = ZSTD_compressBound(size) * 2; + size_t neededBufSize; - seed = FUZZ_seed(src, size); + seed = FUZZ_seed(&src, &size); + neededBufSize = ZSTD_compressBound(size) * 2; /* Allocate all buffers and contexts if not already allocated */ if (neededBufSize > bufSize) { @@ -145,7 +146,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!"); } -#ifndef STATEFULL_FUZZING +#ifndef STATEFUL_FUZZING ZSTD_freeCStream(cstream); cstream = NULL; ZSTD_freeDCtx(dctx); dctx = NULL; #endif From 8b6c80ada8767ff5082f143adda1391a8151e5f6 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 12 Sep 2017 20:21:41 -0700 Subject: [PATCH 132/248] Update fuzzer Makefile --- tests/fuzz/Makefile | 56 +++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/tests/fuzz/Makefile b/tests/fuzz/Makefile index dfb8f1913..0d226eadf 100644 --- a/tests/fuzz/Makefile +++ b/tests/fuzz/Makefile @@ -7,28 +7,28 @@ # in the COPYING file in the root directory of this source tree). # ################################################################ +# Optionally user defined flags CFLAGS ?= -O3 CXXFLAGS ?= -O3 +CPPFLAGS ?= +LDFLAGS ?= +ARFLAGS ?= +LIB_FUZZING_ENGINE ?= libregression.a ZSTDDIR = ../../lib PRGDIR = ../../programs FUZZ_CPPFLAGS := -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/compress \ -I$(ZSTDDIR)/dictBuilder -I$(ZSTDDIR)/deprecated -I$(PRGDIR) \ - -DZSTD_DEBUG=1 -DMEM_FORCE_MEMORY_ACCESS=0 \ - -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION $(CPPFLAGS) -FUZZ_CFLAGS := -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ + $(CPPFLAGS) +FUZZ_EXTRA_FLAGS := -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \ -Wstrict-prototypes -Wundef -Wformat-security \ -Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \ -Wredundant-decls \ - -g -fno-omit-frame-pointer $(CFLAGS) -FUZZ_CXXFLAGS := -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ - -Wstrict-aliasing=1 -Wswitch-enum \ - -Wdeclaration-after-statement -Wstrict-prototypes -Wundef \ - -Wformat-security -Wvla -Wformat=2 -Winit-self -Wfloat-equal \ - -Wwrite-strings -Wredundant-decls \ - -g -fno-omit-frame-pointer -std=c++11 $(CXXFLAGS) + -g -fno-omit-frame-pointer +FUZZ_CFLAGS := $(FUZZ_EXTRA_FLAGS) $(CFLAGS) +FUZZ_CXXFLAGS := $(FUZZ_EXTRA_FLAGS) -std=c++11 $(CXXFLAGS) FUZZ_LDFLAGS := $(LDFLAGS) FUZZ_ARFLAGS := $(ARFLAGS) FUZZ_TARGET_FLAGS = $(FUZZ_CPPFLAGS) $(FUZZ_CXXFLAGS) $(FUZZ_LDFLAGS) @@ -40,9 +40,8 @@ ZSTDCOMP_FILES := $(ZSTDDIR)/compress/*.c ZSTDDECOMP_FILES := $(ZSTDDIR)/decompress/*.c ZSTD_FILES := $(ZSTDDECOMP_FILES) $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES) -ZSTD_OBJ := $(patsubst %.c,%.o, $(wildcard $(ZSTD_FILES))) +ZSTD_OBJ := $(patsubst %.c,%.o, $(wildcard $(ZSTD_FILES))) -LIBFUZZER ?= -lFuzzer .PHONY: default all clean @@ -58,43 +57,20 @@ all: \ $(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $^ -c -o $@ simple_round_trip: $(FUZZ_HEADERS) $(ZSTD_OBJ) simple_round_trip.o - $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) simple_round_trip.o $(LIBFUZZER) -o $@ + $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) simple_round_trip.o $(LIB_FUZZING_ENGINE) -o $@ stream_round_trip: $(FUZZ_HEADERS) $(ZSTD_OBJ) stream_round_trip.o - $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) stream_round_trip.o $(LIBFUZZER) -o $@ + $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) stream_round_trip.o $(LIB_FUZZING_ENGINE) -o $@ simple_decompress: $(FUZZ_HEADERS) $(ZSTD_OBJ) simple_decompress.o - $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) simple_decompress.o $(LIBFUZZER) -o $@ + $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) simple_decompress.o $(LIB_FUZZING_ENGINE) -o $@ stream_decompress: $(FUZZ_HEADERS) $(ZSTD_OBJ) stream_decompress.o - $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) stream_decompress.o $(LIBFUZZER) -o $@ + $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) stream_decompress.o $(LIB_FUZZING_ENGINE) -o $@ libregression.a: $(FUZZ_HEADERS) $(PRGDIR)/util.h regression_driver.o $(AR) $(FUZZ_ARFLAGS) $@ regression_driver.o -%-regression: libregression.a - $(RM) $* - $(MAKE) $* LDFLAGS="$(FUZZ_LDFLAGS) -L." LIBFUZZER=-lregression - -%-regression-test: %-regression - ./$* corpora/$* - -regression-test: \ - simple_round_trip-regression-test \ - stream_round_trip-regression-test \ - simple_decompress-regression-test \ - stream_decompress-regression-test - -%-msan: clean - $(MAKE) $* CFLAGS="-fsanitize=memory $(FUZZ_CFLAGS)" \ - CXXFLAGS="-fsanitize=memory $(FUZZ_CXXFLAGS)" - -UASAN_FLAGS := -fsanitize=address,undefined -fno-sanitize-recover=undefined \ - -fno-sanitize=pointer-overflow -%-uasan: clean - $(MAKE) $* CFLAGS="$(FUZZ_CFLAGS) $(UASAN_FLAGS)" \ - CXXFLAGS="$(FUZZ_CXXFLAGS) $(UASAN_FLAGS)" - # Install libfuzzer (not usable for MSAN testing) # Provided for convienence. To use this library run make libFuzzer and # set LDFLAGS=-L. @@ -102,7 +78,7 @@ UASAN_FLAGS := -fsanitize=address,undefined -fno-sanitize-recover=undefined \ libFuzzer: @$(RM) -rf Fuzzer @git clone https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer - @./Fuzzer/build.sh + @cd Fuzzer && ./build.sh clean: @$(MAKE) -C $(ZSTDDIR) clean From 335780c427e365e1c3c7e7ae96acbf79f9b36f19 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 13 Sep 2017 16:35:29 -0700 Subject: [PATCH 133/248] fixed too strong alignment assert in ZSTD_initStaticCCtx() 64-bits fields are only 32-bits aligned on 32-bits CPU --- lib/compress/zstd_compress.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 9f59ea686..f35a44e4c 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -87,7 +87,7 @@ ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize) { - ZSTD_CCtx* cctx = (ZSTD_CCtx*) workspace; + ZSTD_CCtx* const cctx = (ZSTD_CCtx*) workspace; if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */ if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */ memset(workspace, 0, workspaceSize); /* may be a bit generous, could memset be smaller ? */ @@ -97,7 +97,7 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize) /* entropy space (never moves) */ if (cctx->workSpaceSize < sizeof(ZSTD_entropyCTables_t)) return NULL; - assert(((size_t)cctx->workSpace & 7) == 0); /* ensure correct alignment */ + assert(((size_t)cctx->workSpace & (sizeof(void*)-1)) == 0); /* ensure correct alignment */ cctx->entropy = (ZSTD_entropyCTables_t*)cctx->workSpace; return cctx; From def3214d7496061c4380ac35e9fd8e703f07dd2d Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 13 Sep 2017 17:44:30 -0700 Subject: [PATCH 134/248] [fuzzer] Handle single empty directory --- tests/fuzz/regression_driver.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/fuzz/regression_driver.c b/tests/fuzz/regression_driver.c index 36ae3884f..2b714d29e 100644 --- a/tests/fuzz/regression_driver.c +++ b/tests/fuzz/regression_driver.c @@ -29,9 +29,11 @@ int main(int argc, char const **argv) { #ifdef UTIL_HAS_CREATEFILELIST files = UTIL_createFileList(files, numFiles, &fileNamesBuf, &numFiles, kFollowLinks); - FUZZ_ASSERT(files); + if (!files) + numFiles = 0; #endif - + if (numFiles == 0) + fprintf(stderr, "WARNING: No files passed to %s\n", argv[0]); for (i = 0; i < numFiles; ++i) { char const *fileName = files[i]; size_t const fileSize = UTIL_getFileSize(fileName); From b7e152233044de7e147864c6b239c850820e543d Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 13 Sep 2017 17:44:41 -0700 Subject: [PATCH 135/248] Add block fuzzers --- tests/fuzz/Makefile | 10 +++- tests/fuzz/block_decompress.c | 51 ++++++++++++++++++ tests/fuzz/block_round_trip.c | 99 +++++++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 tests/fuzz/block_decompress.c create mode 100644 tests/fuzz/block_round_trip.c diff --git a/tests/fuzz/Makefile b/tests/fuzz/Makefile index 0d226eadf..c7d221f3c 100644 --- a/tests/fuzz/Makefile +++ b/tests/fuzz/Makefile @@ -50,8 +50,10 @@ default: all all: \ simple_round_trip \ stream_round_trip \ + block_round_trip \ simple_decompress \ - stream_decompress + stream_decompress \ + block_decompress %.o: %.c $(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $^ -c -o $@ @@ -62,12 +64,18 @@ simple_round_trip: $(FUZZ_HEADERS) $(ZSTD_OBJ) simple_round_trip.o stream_round_trip: $(FUZZ_HEADERS) $(ZSTD_OBJ) stream_round_trip.o $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) stream_round_trip.o $(LIB_FUZZING_ENGINE) -o $@ +block_round_trip: $(FUZZ_HEADERS) $(ZSTD_OBJ) block_round_trip.o + $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) block_round_trip.o $(LIB_FUZZING_ENGINE) -o $@ + simple_decompress: $(FUZZ_HEADERS) $(ZSTD_OBJ) simple_decompress.o $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) simple_decompress.o $(LIB_FUZZING_ENGINE) -o $@ stream_decompress: $(FUZZ_HEADERS) $(ZSTD_OBJ) stream_decompress.o $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) stream_decompress.o $(LIB_FUZZING_ENGINE) -o $@ +block_decompress: $(FUZZ_HEADERS) $(ZSTD_OBJ) block_decompress.o + $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) block_decompress.o $(LIB_FUZZING_ENGINE) -o $@ + libregression.a: $(FUZZ_HEADERS) $(PRGDIR)/util.h regression_driver.o $(AR) $(FUZZ_ARFLAGS) $@ regression_driver.o diff --git a/tests/fuzz/block_decompress.c b/tests/fuzz/block_decompress.c new file mode 100644 index 000000000..3cccc32f4 --- /dev/null +++ b/tests/fuzz/block_decompress.c @@ -0,0 +1,51 @@ +/** + * 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). + */ + +/** + * This fuzz target attempts to decompress the fuzzed data with the simple + * decompression function to ensure the decompressor never crashes. + */ + +#define ZSTD_STATIC_LINKING_ONLY + +#include +#include +#include +#include "fuzz_helpers.h" +#include "zstd.h" + +static ZSTD_DCtx *dctx = NULL; +static void* rBuf = NULL; +static size_t bufSize = 0; + +int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) +{ + size_t const neededBufSize = ZSTD_BLOCKSIZE_MAX; + + FUZZ_seed(&src, &size); + + /* Allocate all buffers and contexts if not already allocated */ + if (neededBufSize > bufSize) { + free(rBuf); + rBuf = malloc(neededBufSize); + bufSize = neededBufSize; + FUZZ_ASSERT(rBuf); + } + if (!dctx) { + dctx = ZSTD_createDCtx(); + FUZZ_ASSERT(dctx); + } + ZSTD_decompressBegin(dctx); + ZSTD_decompressBlock(dctx, rBuf, neededBufSize, src, size); + +#ifndef STATEFUL_FUZZING + ZSTD_freeDCtx(dctx); dctx = NULL; +#endif + return 0; +} diff --git a/tests/fuzz/block_round_trip.c b/tests/fuzz/block_round_trip.c new file mode 100644 index 000000000..3b3f2ff65 --- /dev/null +++ b/tests/fuzz/block_round_trip.c @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2016-present, 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). + */ + +/** + * This fuzz target performs a zstd round-trip test (compress & decompress), + * compares the result with the original, and calls abort() on corruption. + */ + +#define ZSTD_STATIC_LINKING_ONLY + +#include +#include +#include +#include +#include "fuzz_helpers.h" +#include "zstd.h" + +static const int kMaxClevel = 19; + +static ZSTD_CCtx *cctx = NULL; +static ZSTD_DCtx *dctx = NULL; +static void* cBuf = NULL; +static void* rBuf = NULL; +static size_t bufSize = 0; +static uint32_t seed; + +static size_t roundTripTest(void *result, size_t resultCapacity, + void *compressed, size_t compressedCapacity, + const void *src, size_t srcSize) +{ + int const cLevel = FUZZ_rand(&seed) % kMaxClevel; + size_t ret = ZSTD_compressBegin(cctx, cLevel); + + if (ZSTD_isError(ret)) { + fprintf(stderr, "ZSTD_compressBegin() error: %s\n", + ZSTD_getErrorName(ret)); + return ret; + } + + ret = ZSTD_compressBlock(cctx, compressed, compressedCapacity, src, srcSize); + if (ZSTD_isError(ret)) { + fprintf(stderr, "ZSTD_compressBlock() error: %s\n", ZSTD_getErrorName(ret)); + return ret; + } + if (ret == 0) { + FUZZ_ASSERT(resultCapacity >= srcSize); + memcpy(result, src, srcSize); + return srcSize; + } + ZSTD_decompressBegin(dctx); + return ZSTD_decompressBlock(dctx, result, resultCapacity, compressed, ret); +} + +int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) +{ + size_t neededBufSize; + + seed = FUZZ_seed(&src, &size); + neededBufSize = size; + if (size > ZSTD_BLOCKSIZE_MAX) + return 0; + + /* Allocate all buffers and contexts if not already allocated */ + if (neededBufSize > bufSize || !cBuf || !rBuf) { + free(cBuf); + free(rBuf); + cBuf = malloc(neededBufSize); + rBuf = malloc(neededBufSize); + bufSize = neededBufSize; + FUZZ_ASSERT(cBuf && rBuf); + } + if (!cctx) { + cctx = ZSTD_createCCtx(); + FUZZ_ASSERT(cctx); + } + if (!dctx) { + dctx = ZSTD_createDCtx(); + FUZZ_ASSERT(dctx); + } + + { + size_t const result = + roundTripTest(rBuf, neededBufSize, cBuf, neededBufSize, src, size); + FUZZ_ASSERT_MSG(!ZSTD_isError(result), ZSTD_getErrorName(result)); + FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size"); + FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!"); + } +#ifndef STATEFUL_FUZZING + ZSTD_freeCCtx(cctx); cctx = NULL; + ZSTD_freeDCtx(dctx); dctx = NULL; +#endif + return 0; +} From 6b8236cf7e5eefb5a24341039a6bd7de89722372 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 13 Sep 2017 17:45:21 -0700 Subject: [PATCH 136/248] [fuzz] Add fuzzing helper script --- tests/fuzz/fuzz.py | 717 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 717 insertions(+) create mode 100755 tests/fuzz/fuzz.py diff --git a/tests/fuzz/fuzz.py b/tests/fuzz/fuzz.py new file mode 100755 index 000000000..1384bc48e --- /dev/null +++ b/tests/fuzz/fuzz.py @@ -0,0 +1,717 @@ +#! /usr/bin/env python + +# ################################################################ +# Copyright (c) 2016-present, 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). +# ########################################################################## + +import argparse +import contextlib +import os +import re +import shutil +import subprocess +import sys +import tempfile + + +def abs_join(a, *p): + return os.path.abspath(os.path.join(a, *p)) + + +# Constants +FUZZ_DIR = os.path.abspath(os.path.dirname(__file__)) +CORPORA_DIR = abs_join(FUZZ_DIR, 'corpora') +TARGETS = [ + 'simple_round_trip', + 'stream_round_trip', + 'block_round_trip', + 'simple_decompress', + 'stream_decompress', + 'block_decompress', +] +ALL_TARGETS = TARGETS + ['all'] +FUZZ_RNG_SEED_SIZE = 4 + +# Standard environment variables +CC = os.environ.get('CC', 'cc') +CXX = os.environ.get('CXX', 'c++') +CPPFLAGS = os.environ.get('CPPFLAGS', '') +CFLAGS = os.environ.get('CFLAGS', '-O3') +CXXFLAGS = os.environ.get('CXXFLAGS', CFLAGS) +LDFLAGS = os.environ.get('LDFLAGS', '') +MFLAGS = os.environ.get('MFLAGS', '-j') + +# Fuzzing environment variables +LIB_FUZZING_ENGINE = os.environ.get('LIB_FUZZING_ENGINE', 'libregression.a') +AFL_FUZZ = os.environ.get('AFL_FUZZ', 'afl-fuzz') +DECODECORPUS = os.environ.get('DECODECORPUS', + abs_join(FUZZ_DIR, '..', 'decodecorpus')) + +# Sanitizer environment variables +MSAN_EXTRA_CPPFLAGS = os.environ.get('MSAN_EXTRA_CPPFLAGS', '') +MSAN_EXTRA_CFLAGS = os.environ.get('MSAN_EXTRA_CFLAGS', '') +MSAN_EXTRA_CXXFLAGS = os.environ.get('MSAN_EXTRA_CXXFLAGS', '') +MSAN_EXTRA_LDFLAGS = os.environ.get('MSAN_EXTRA_LDFLAGS', '') + + +def create(r): + d = os.path.abspath(r) + if not os.path.isdir(d): + os.mkdir(d) + return d + + +def check(r): + d = os.path.abspath(r) + if not os.path.isdir(d): + return None + return d + + +@contextlib.contextmanager +def tmpdir(): + dirpath = tempfile.mkdtemp() + try: + yield dirpath + finally: + shutil.rmtree(dirpath, ignore_errors=True) + + +def parse_env_flags(args, flags): + """ + Look for flags set by environment variables. + """ + flags = ' '.join(flags) + san_flags = ','.join(re.findall('-fsanitize=((?:[a-z]+,?)+)', flags)) + nosan_flags = ','.join(re.findall('-fno-sanitize=((?:[a-z]+,?)+)', flags)) + + def set_sanitizer(sanitizer, default, san, nosan): + if sanitizer in san and sanitizer in nosan: + raise RuntimeError('-fno-sanitize={s} and -fsanitize={s} passed'. + format(s=sanitizer)) + if sanitizer in san: + return True + if sanitizer in nosan: + return False + return default + + san = set(san_flags.split(',')) + nosan = set(nosan_flags.split(',')) + + args.asan = set_sanitizer('address', args.asan, san, nosan) + args.msan = set_sanitizer('memory', args.msan, san, nosan) + args.ubsan = set_sanitizer('undefined', args.ubsan, san, nosan) + + args.sanitize = args.asan or args.msan or args.ubsan + + return args + + +def build_parser(args): + description = """ + Cleans the repository and builds a fuzz target (or all). + Many flags default to environment variables (default says $X='y'). + Options that aren't enabling features default to the correct values for + zstd. + Enable sanitizers with --enable-*san. + For regression testing just build. + For libFuzzer set LIB_FUZZING_ENGINE and pass --enable-coverage. + For AFL set CC and CXX to AFL's compilers and set + LIB_FUZZING_ENGINE='libregression.a'. + """ + parser = argparse.ArgumentParser(prog=args.pop(0), description=description) + parser.add_argument( + '--lib-fuzzing-engine', + dest='lib_fuzzing_engine', + type=str, + default=LIB_FUZZING_ENGINE, + help=('The fuzzing engine to use e.g. /path/to/libFuzzer.a ' + "(default: $LIB_FUZZING_ENGINE='{})".format(LIB_FUZZING_ENGINE))) + parser.add_argument( + '--enable-coverage', + dest='coverage', + action='store_true', + help='Enable coverage instrumentation (-fsanitize-coverage)') + parser.add_argument( + '--enable-asan', dest='asan', action='store_true', help='Enable UBSAN') + parser.add_argument( + '--enable-ubsan', + dest='ubsan', + action='store_true', + help='Enable UBSAN') + parser.add_argument( + '--enable-ubsan-pointer-overflow', + dest='ubsan_pointer_overflow', + action='store_true', + help='Enable UBSAN pointer overflow check (known failure)') + parser.add_argument( + '--enable-msan', dest='msan', action='store_true', help='Enable MSAN') + parser.add_argument( + '--enable-msan-track-origins', dest='msan_track_origins', + action='store_true', help='Enable MSAN origin tracking') + parser.add_argument( + '--msan-extra-cppflags', + dest='msan_extra_cppflags', + type=str, + default=MSAN_EXTRA_CPPFLAGS, + help="Extra CPPFLAGS for MSAN (default: $MSAN_EXTRA_CPPFLAGS='{}')". + format(MSAN_EXTRA_CPPFLAGS)) + parser.add_argument( + '--msan-extra-cflags', + dest='msan_extra_cflags', + type=str, + default=MSAN_EXTRA_CFLAGS, + help="Extra CFLAGS for MSAN (default: $MSAN_EXTRA_CFLAGS='{}')".format( + MSAN_EXTRA_CFLAGS)) + parser.add_argument( + '--msan-extra-cxxflags', + dest='msan_extra_cxxflags', + type=str, + default=MSAN_EXTRA_CXXFLAGS, + help="Extra CXXFLAGS for MSAN (default: $MSAN_EXTRA_CXXFLAGS='{}')". + format(MSAN_EXTRA_CXXFLAGS)) + parser.add_argument( + '--msan-extra-ldflags', + dest='msan_extra_ldflags', + type=str, + default=MSAN_EXTRA_LDFLAGS, + help="Extra LDFLAGS for MSAN (default: $MSAN_EXTRA_LDFLAGS='{}')". + format(MSAN_EXTRA_LDFLAGS)) + parser.add_argument( + '--enable-sanitize-recover', + dest='sanitize_recover', + action='store_true', + help='Non-fatal sanitizer errors where possible') + parser.add_argument( + '--debug', + dest='debug', + type=int, + default=1, + help='Set ZSTD_DEBUG (default: 1)') + parser.add_argument( + '--force-memory-access', + dest='memory_access', + type=int, + default=0, + help='Set MEM_FORCE_MEMORY_ACCESS (default: 0)') + parser.add_argument( + '--fuzz-rng-seed-size', + dest='fuzz_rng_seed_size', + type=int, + default=4, + help='Set FUZZ_RNG_SEED_SIZE (default: 4)') + parser.add_argument( + '--disable-fuzzing-mode', + dest='fuzzing_mode', + action='store_false', + help='Do not define FUZZING_BUILD_MORE_UNSAFE_FOR_PRODUCTION') + parser.add_argument( + '--enable-stateful-fuzzing', + dest='stateful_fuzzing', + action='store_true', + help='Reuse contexts between runs (makes reproduction impossible)') + parser.add_argument( + '--cc', + dest='cc', + type=str, + default=CC, + help="CC (default: $CC='{}')".format(CC)) + parser.add_argument( + '--cxx', + dest='cxx', + type=str, + default=CXX, + help="CXX (default: $CXX='{}')".format(CXX)) + parser.add_argument( + '--cppflags', + dest='cppflags', + type=str, + default=CPPFLAGS, + help="CPPFLAGS (default: $CPPFLAGS='{}')".format(CPPFLAGS)) + parser.add_argument( + '--cflags', + dest='cflags', + type=str, + default=CFLAGS, + help="CFLAGS (default: $CFLAGS='{}')".format(CFLAGS)) + parser.add_argument( + '--cxxflags', + dest='cxxflags', + type=str, + default=CXXFLAGS, + help="CXXFLAGS (default: $CXXFLAGS='{}')".format(CXXFLAGS)) + parser.add_argument( + '--ldflags', + dest='ldflags', + type=str, + default=LDFLAGS, + help="LDFLAGS (default: $LDFLAGS='{}')".format(LDFLAGS)) + parser.add_argument( + '--mflags', + dest='mflags', + type=str, + default=MFLAGS, + help="Extra Make flags (default: $MFLAGS='{}')".format(MFLAGS)) + parser.add_argument( + 'TARGET', + nargs='*', + type=str, + help='Fuzz target(s) to build {{{}}}'.format(', '.join(ALL_TARGETS)) + ) + args = parser.parse_args(args) + args = parse_env_flags(args, ' '.join( + [args.cppflags, args.cflags, args.cxxflags, args.ldflags])) + + # Check option sanitiy + if args.msan and (args.asan or args.ubsan): + raise RuntimeError('MSAN may not be used with any other sanitizers') + if args.msan_track_origins and not args.msan: + raise RuntimeError('--enable-msan-track-origins requires MSAN') + if args.ubsan_pointer_overflow and not args.ubsan: + raise RuntimeError('--enable-ubsan-pointer-overlow requires UBSAN') + if args.sanitize_recover and not args.sanitize: + raise RuntimeError('--enable-sanitize-recover but no sanitizers used') + + return args + + +def build(args): + try: + args = build_parser(args) + except Exception as e: + print(e) + return 1 + # The compilation flags we are setting + targets = args.TARGET + cc = args.cc + cxx = args.cxx + cppflags = [args.cppflags] + cflags = [args.cflags] + ldflags = [args.ldflags] + cxxflags = [args.cxxflags] + mflags = [args.mflags] if args.mflags else [] + # Flags to be added to both cflags and cxxflags + common_flags = [] + + cppflags += [ + '-DZSTD_DEBUG={}'.format(args.debug), + '-DMEM_FORCE_MEMORY_ACCESS={}'.format(args.memory_access), + '-DFUZZ_RNG_SEED_SIZE={}'.format(args.fuzz_rng_seed_size), + ] + + mflags += ['LIB_FUZZING_ENGINE={}'.format(args.lib_fuzzing_engine)] + + # Set flags for options + if args.coverage: + common_flags += [ + '-fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp' + ] + + if args.sanitize_recover: + recover_flags = ['-fsanitize-recover=all'] + else: + recover_flags = ['-fno-sanitize-recover=all'] + if args.sanitize: + common_flags += recover_flags + + if args.msan: + msan_flags = ['-fsanitize=memory'] + if args.msan_track_origins: + msan_flags += ['-fsanitize-memory-track-origins'] + common_flags += msan_flags + # Append extra MSAN flags (it might require special setup) + cppflags += [args.msan_extra_cppflags] + cflags += [args.msan_extra_cflags] + cxxflags += [args.msan_extra_cxxflags] + ldflags += [args.msan_extra_ldflags] + + if args.asan: + common_flags += ['-fsanitize=address'] + + if args.ubsan: + ubsan_flags = ['-fsanitize=undefined'] + if not args.ubsan_pointer_overflow: + ubsan_flags += ['-fno-sanitize=pointer-overflow'] + common_flags += ubsan_flags + + if args.stateful_fuzzing: + cppflags += ['-DSTATEFUL_FUZZING'] + + if args.fuzzing_mode: + cppflags += ['-DFUZZING_BUILD_MORE_UNSAFE_FOR_PRODUCTION'] + + if args.lib_fuzzing_engine == 'libregression.a': + targets = ['libregression.a'] + targets + + # Append the common flags + cflags += common_flags + cxxflags += common_flags + + # Prepare the flags for Make + cc_str = "CC={}".format(cc) + cxx_str = "CXX={}".format(cxx) + cppflags_str = "CPPFLAGS={}".format(' '.join(cppflags)) + cflags_str = "CFLAGS={}".format(' '.join(cflags)) + cxxflags_str = "CXXFLAGS={}".format(' '.join(cxxflags)) + ldflags_str = "LDFLAGS={}".format(' '.join(ldflags)) + + # Print the flags + print('MFLAGS={}'.format(' '.join(mflags))) + print(cc_str) + print(cxx_str) + print(cppflags_str) + print(cflags_str) + print(cxxflags_str) + print(ldflags_str) + + # Clean and build + clean_cmd = ['make', 'clean'] + mflags + print(' '.join(clean_cmd)) + subprocess.check_call(clean_cmd) + build_cmd = [ + 'make', + cc_str, + cxx_str, + cppflags_str, + cflags_str, + cxxflags_str, + ldflags_str, + ] + mflags + targets + print(' '.join(build_cmd)) + subprocess.check_call(build_cmd) + return 0 + + +def libfuzzer_parser(args): + description = """ + Runs a libfuzzer binary. + Passes all extra arguments to libfuzzer. + The fuzzer should have been build with LIB_FUZZING_ENGINE pointing to + libFuzzer.a. + Generates output in the CORPORA directory, puts crashes in the ARTIFACT + directory, and takes extra input from the SEED directory. + To merge AFL's output pass the SEED as AFL's output directory and pass + '-merge=1'. + """ + parser = argparse.ArgumentParser(prog=args.pop(0), description=description) + parser.add_argument( + '--corpora', + type=str, + help='Override the default corpora dir (default: {})'.format( + abs_join(CORPORA_DIR, 'TARGET'))) + parser.add_argument( + '--artifact', + type=str, + help='Override the default artifact dir (default: {})'.format( + abs_join(CORPORA_DIR, 'TARGET-crash'))) + parser.add_argument( + '--seed', + type=str, + help='Override the default seed dir (default: {})'.format( + abs_join(CORPORA_DIR, 'TARGET-seed'))) + parser.add_argument( + 'TARGET', + type=str, + help='Fuzz target(s) to build {{{}}}'.format(', '.join(TARGETS))) + args, extra = parser.parse_known_args(args) + args.extra = extra + + if args.TARGET and args.TARGET not in TARGETS: + raise RuntimeError('{} is not a valid target'.format(args.TARGET)) + + if not args.corpora: + args.corpora = abs_join(CORPORA_DIR, args.TARGET) + if not args.artifact: + args.artifact = abs_join(CORPORA_DIR, '{}-crash'.format(args.TARGET)) + if not args.seed: + args.seed = abs_join(CORPORA_DIR, '{}-seed'.format(args.TARGET)) + + return args + + +def libfuzzer(args): + try: + args = libfuzzer_parser(args) + except Exception as e: + print(e) + return 1 + target = abs_join(FUZZ_DIR, args.TARGET) + + corpora = [create(args.corpora)] + artifact = create(args.artifact) + seed = check(args.seed) + + corpora += [artifact] + if seed is not None: + corpora += [seed] + + cmd = [target, '-artifact_prefix={}/'.format(artifact)] + cmd += corpora + args.extra + print(' '.join(cmd)) + subprocess.call(cmd) + return 0 + + +def afl_parser(args): + description = """ + Runs an afl-fuzz job. + Passes all extra arguments to afl-fuzz. + The fuzzer should have been built with CC/CXX set to the AFL compilers, + and with LIB_FUZZING_ENGINE='libregression.a'. + Takes input from CORPORA and writes output to OUTPUT. + Uses AFL_FUZZ as the binary (set from flag or environment variable). + """ + parser = argparse.ArgumentParser(prog=args.pop(0), description=description) + parser.add_argument( + '--corpora', + type=str, + help='Override the default corpora dir (default: {})'.format( + abs_join(CORPORA_DIR, 'TARGET'))) + parser.add_argument( + '--output', + type=str, + help='Override the default AFL output dir (default: {})'.format( + abs_join(CORPORA_DIR, 'TARGET-afl'))) + parser.add_argument( + '--afl-fuzz', + type=str, + default=AFL_FUZZ, + help='AFL_FUZZ (default: $AFL_FUZZ={})'.format(AFL_FUZZ)) + parser.add_argument( + 'TARGET', + type=str, + help='Fuzz target(s) to build {{{}}}'.format(', '.join(TARGETS))) + args, extra = parser.parse_known_args(args) + args.extra = extra + + if args.TARGET and args.TARGET not in TARGETS: + raise RuntimeError('{} is not a valid target'.format(args.TARGET)) + + if not args.corpora: + args.corpora = abs_join(CORPORA_DIR, args.TARGET) + if not args.output: + args.output = abs_join(CORPORA_DIR, '{}-afl'.format(args.TARGET)) + + return args + + +def afl(args): + try: + args = afl_parser(args) + except Exception as e: + print(e) + return 1 + target = abs_join(FUZZ_DIR, args.TARGET) + + corpora = create(args.corpora) + output = create(args.output) + + cmd = [args.afl_fuzz, '-i', corpora, '-o', output] + args.extra + cmd += [target, '@@'] + print(' '.join(cmd)) + subprocess.call(cmd) + return 0 + + +def regression_parser(args): + description = """ + Runs one or more regression tests. + The fuzzer should have been built with with + LIB_FUZZING_ENGINE='libregression.a'. + Takes input from CORPORA. + """ + parser = argparse.ArgumentParser(prog=args.pop(0), description=description) + parser.add_argument( + 'TARGET', + nargs='*', + type=str, + help='Fuzz target(s) to build {{{}}}'.format(', '.join(ALL_TARGETS))) + args = parser.parse_args(args) + + targets = set() + for target in args.TARGET: + if not target: + continue + if target == 'all': + targets = targets.union(TARGETS) + elif target in TARGETS: + targets = targets.add(target) + else: + raise RuntimeError('{} is not a valid target'.format(target)) + args.TARGET = list(targets) + + return args + + +def regression(args): + try: + args = regression_parser(args) + except Exception as e: + print(e) + return 1 + for target in args.TARGET: + corpora = create(abs_join(CORPORA_DIR, target)) + target = abs_join(FUZZ_DIR, target) + cmd = [target, corpora] + print(' '.join(cmd)) + subprocess.check_call(cmd) + return 0 + + +def gen_parser(args): + description = """ + Generate a seed corpus appropiate for TARGET with data generated with + decodecorpus. + The fuzz inputs are prepended with a seed before the zstd data, so the + output of decodecorpus shouldn't be used directly. + Generates NUMBER samples prepended with FUZZ_RNG_SEED_SIZE random bytes and + puts the output in SEED. + DECODECORPUS is the decodecorpus binary, and must already be built. + """ + parser = argparse.ArgumentParser(prog=args.pop(0), description=description) + parser.add_argument( + '--number', + '-n', + type=int, + default=100, + help='Number of samples to generate') + parser.add_argument( + '--max-size-log', + type=int, + default=13, + help='Maximum sample size to generate') + parser.add_argument( + '--seed', + type=str, + help='Override the default seed dir (default: {})'.format( + abs_join(CORPORA_DIR, 'TARGET-seed'))) + parser.add_argument( + '--decodecorpus', + type=str, + default=DECODECORPUS, + help="decodecorpus binary (default: $DECODECORPUS='{}')".format( + DECODECORPUS)) + parser.add_argument( + '--fuzz-rng-seed-size', + type=int, + default=4, + help="FUZZ_RNG_SEED_SIZE used for generate the samples (must match)" + ) + parser.add_argument( + 'TARGET', + type=str, + help='Fuzz target(s) to build {{{}}}'.format(', '.join(TARGETS))) + args, extra = parser.parse_known_args(args) + args.extra = extra + + if args.TARGET and args.TARGET not in TARGETS: + raise RuntimeError('{} is not a valid target'.format(args.TARGET)) + + if not args.seed: + args.seed = abs_join(CORPORA_DIR, '{}-seed'.format(args.TARGET)) + + if not os.path.isfile(args.decodecorpus): + raise RuntimeError("{} is not a file run 'make -C {} decodecorpus'". + format(args.decodecorpus, abs_join(FUZZ_DIR, '..'))) + + return args + + +def gen(args): + try: + args = gen_parser(args) + except Exception as e: + print(e) + return 1 + + seed = create(args.seed) + with tmpdir() as compressed: + with tmpdir() as decompressed: + cmd = [ + args.decodecorpus, + '-n{}'.format(args.number), + '--max-content-size-log={}'.format(args.max_size_log), + '-p{}/'.format(compressed), + '-o{}'.format(decompressed), + ] + + if 'block_' in args.TARGET: + cmd += ['--gen-blocks'] + + print(' '.join(cmd)) + subprocess.check_call(cmd) + + if '_round_trip' in args.TARGET: + print('using decompressed data in {}'.format(decompressed)) + samples = decompressed + elif '_decompress' in args.TARGET: + print('using compressed data in {}'.format(compressed)) + samples = compressed + + # Copy the samples over and prepend the RNG seeds + for name in os.listdir(samples): + samplename = abs_join(samples, name) + outname = abs_join(seed, name) + rng_seed = os.urandom(args.fuzz_rng_seed_size) + with open(samplename, 'rb') as sample: + with open(outname, 'wb') as out: + out.write(rng_seed) + CHUNK_SIZE = 131072 + chunk = sample.read(CHUNK_SIZE) + while len(chunk) > 0: + out.write(chunk) + chunk = sample.read(CHUNK_SIZE) + return 0 + + +def short_help(args): + name = args[0] + print("Usage: {} [OPTIONS] COMMAND [ARGS]...\n".format(name)) + + +def help(args): + short_help(args) + print("\tfuzzing helpers (select a command and pass -h for help)\n") + print("Options:") + print("\t-h, --help\tPrint this message") + print("") + print("Commands:") + print("\tbuild\t\tBuild a fuzzer") + print("\tlibfuzzer\tRun a libFuzzer fuzzer") + print("\tafl\t\tRun an AFL fuzzer") + print("\tregression\tRun a regression test") + print("\tgen\t\tGenerate a seed corpus for a fuzzer") + + +def main(): + args = sys.argv + if len(args) < 2: + help(args) + return 1 + if args[1] == '-h' or args[1] == '--help' or args[1] == '-H': + help(args) + return 1 + command = args.pop(1) + args[0] = "{} {}".format(args[0], command) + if command == "build": + return build(args) + if command == "libfuzzer": + return libfuzzer(args) + if command == "regression": + return regression(args) + if command == "afl": + return afl(args) + if command == "gen": + return gen(args) + short_help(args) + print("Error: No such command {} (pass -h for help)".format(command)) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) From 6c6412cef950ba29985fb695700cbea4be93fcf4 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 13 Sep 2017 18:18:35 -0700 Subject: [PATCH 137/248] [fuzzer] Update README.md --- tests/fuzz/README.md | 86 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 16 deletions(-) diff --git a/tests/fuzz/README.md b/tests/fuzz/README.md index 38a4f3d1a..6d0fab556 100644 --- a/tests/fuzz/README.md +++ b/tests/fuzz/README.md @@ -2,33 +2,87 @@ Each fuzzing target can be built with multiple engines. +## fuzz.py + +`fuzz.py` is a helper script for building and running fuzzers. +Run `./fuzz.py -h` for the commands and run `./fuzz.py COMMAND -h` for +command specific help. + +### Generating Data + +`fuzz.py` provides a utility to generate seed data for each fuzzer. + +``` +make -C ../tests decodecorpus +./fuzz.py gen TARGET +``` + +By default it outputs 100 samples, each at most 8KB into `corpora/TARGET-seed`, +but that can be configured with the `--number`, `--max-size-log` and `--seed` +flags. + +### Build +It respects the usual build environment variables `CC`, `CFLAGS`, etc. +The environment variables can be overridden with the corresponding flags +`--cc`, `--cflags`, etc. +The specific fuzzing engine is selected with `LIB_FUZZING_ENGINE` or +`--lib-fuzzing-engine`, the default is `libregression.a`. +It has flags that can easily set up sanitizers `--enable-{a,ub,m}san`, and +coverage instrumentation `--enable-coverage`. +It sets sane defaults which can be overriden with flags `--debug`, +`--enable-ubsan-pointer-overlow`, etc. +Run `./fuzz.py build -h` for help. + +### Running Fuzzers + +`./fuzz.py` can run `libfuzzer`, `afl`, and `regression` tests. +See the help of the relevant command for options. +Flags not parsed by `fuzz.py` are passed to the fuzzing engine. +The command used to run the fuzzer is printed for debugging. + ## LibFuzzer -You can install `libFuzzer` with `make libFuzzer`. Then you can make each target -with `make target LDFLAGS=-L. CC=clang CXX=clang++`. +``` +# Build libfuzzer if necessary +make libFuzzer +# Build the fuzz targets +./fuzz.py build all --enable-coverage --enable-asan --enable-ubsan --lib-fuzzing-engine Fuzzer/libFuzzer.a --cc clang --cxx clang++ +# OR equivalently +CC=clang CXX=clang++ LIB_FUZZING_ENGINE=Fuzzer/libFuzzer.a ./fuzz.py build all --enable-coverage --enable-asan --enable-ubsan +# Run the fuzzer +./fuzz.py libfuzzer TARGET -max_len=8192 -jobs=4 +``` + +where `TARGET` could be `simple_decompress`, `stream_round_trip`, etc. + +### MSAN + +Fuzzing with `libFuzzer` and `MSAN` will require building a C++ standard library +and libFuzzer with MSAN. +`fuzz.py` respects the environment variables / flags `MSAN_EXTRA_CPPFLAGS`, +`MSAN_EXTRA_CFLAGS`, `MSAN_EXTRA_CXXFLAGS`, `MSAN_EXTRA_LDFLAGS` to easily pass +the extra parameters only for MSAN. ## AFL -The regression driver also serves as a binary for `afl-fuzz`. You can make each -target with one of these commands: +The default `LIB_FUZZING_ENGINE` is `libregression.a`, which produces a binary +that AFL can use. ``` -make target-regression CC=afl-clang CXX=afl-clang++ -AFL_MSAN=1 make target-regression-msan CC=afl-clang CXX=afl-clang++ -AFL_ASAN=1 make target-regression-uasan CC=afl-clang CXX=afl-clang++ +# Build the fuzz targets +CC=afl-clang CXX=afl-clang++ ./fuzz.py build all --enable-asan --enable-ubsan +# Run the fuzzer without a memory limit because of ASAN +./fuzz.py afl TARGET -m none ``` -Then run as `./target @@`. - ## Regression Testing -Each fuzz target has a corpus checked into the repo under `fuzz/corpora/`. -You can run regression tests on the corpora to ensure that inputs which -previously exposed bugs still pass. You can make these targets to run the -regression tests with different sanitizers. +The regression rest supports the `all` target to run all the fuzzers in one +command. ``` -make regression-test -make regression-test-msan -make regression-test-uasan +CC=clang CXX=clang++ ./fuzz.py build all --enable-asan --enable-ubsan +./fuzz.py regression all +CC=clang CXX=clang++ ./fuzz.py build all --enable-msan +./fuzz.py regression all ``` From a6f08b4783646deacc72fc700613ff150fa65d36 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 13 Sep 2017 18:41:32 -0700 Subject: [PATCH 138/248] [fuzzer] Fix FUZZ_seed() --- tests/fuzz/fuzz_helpers.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/fuzz/fuzz_helpers.h b/tests/fuzz/fuzz_helpers.h index d93881c80..cb3421bb8 100644 --- a/tests/fuzz/fuzz_helpers.h +++ b/tests/fuzz/fuzz_helpers.h @@ -55,10 +55,11 @@ extern "C" { * Consumes up to the first FUZZ_RNG_SEED_SIZE bytes of the input. */ FUZZ_STATIC uint32_t FUZZ_seed(uint8_t const **src, size_t* size) { + uint8_t const *data = *src; size_t const toHash = MIN(FUZZ_RNG_SEED_SIZE, *size); - return XXH32(*src, toHash, 0); *size -= toHash; *src += toHash; + return XXH32(data, toHash, 0); } #define FUZZ_rotl32(x, r) (((x) << (r)) | ((x) >> (32 - (r)))) From 9712d5ebe62186e29fd6cbb3d1f6ec4f338c9576 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 13 Sep 2017 19:08:35 -0700 Subject: [PATCH 139/248] [fuzzer] Fix bugs in fuzz.py --- tests/fuzz/fuzz.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/fuzz/fuzz.py b/tests/fuzz/fuzz.py index 1384bc48e..0ce201cdd 100755 --- a/tests/fuzz/fuzz.py +++ b/tests/fuzz/fuzz.py @@ -540,7 +540,7 @@ def regression_parser(args): if target == 'all': targets = targets.union(TARGETS) elif target in TARGETS: - targets = targets.add(target) + targets.add(target) else: raise RuntimeError('{} is not a valid target'.format(target)) args.TARGET = list(targets) @@ -635,13 +635,17 @@ def gen(args): cmd = [ args.decodecorpus, '-n{}'.format(args.number), - '--max-content-size-log={}'.format(args.max_size_log), '-p{}/'.format(compressed), '-o{}'.format(decompressed), ] if 'block_' in args.TARGET: - cmd += ['--gen-blocks'] + cmd += [ + '--gen-blocks', + '--max-block-size-log={}'.format(args.max_size_log) + ] + else: + cmd += ['--max-content-size-log={}'.format(args.max_size_log)] print(' '.join(cmd)) subprocess.check_call(cmd) From 39357c41cba8501da6e681b03b6b1ff2763de744 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 14 Sep 2017 14:41:49 -0700 Subject: [PATCH 140/248] [fuzzer] Fuzz long range matching & new API --- tests/fuzz/Makefile | 41 ++++++------ tests/fuzz/fuzz_helpers.h | 37 +++++++---- tests/fuzz/simple_round_trip.c | 34 +++++++--- tests/fuzz/stream_round_trip.c | 115 +++++++++++++++++---------------- tests/fuzz/zstd_helpers.c | 46 +++++++++++++ tests/fuzz/zstd_helpers.h | 31 +++++++++ 6 files changed, 209 insertions(+), 95 deletions(-) create mode 100644 tests/fuzz/zstd_helpers.c create mode 100644 tests/fuzz/zstd_helpers.h diff --git a/tests/fuzz/Makefile b/tests/fuzz/Makefile index c7d221f3c..60822d498 100644 --- a/tests/fuzz/Makefile +++ b/tests/fuzz/Makefile @@ -33,14 +33,19 @@ FUZZ_LDFLAGS := $(LDFLAGS) FUZZ_ARFLAGS := $(ARFLAGS) FUZZ_TARGET_FLAGS = $(FUZZ_CPPFLAGS) $(FUZZ_CXXFLAGS) $(FUZZ_LDFLAGS) -FUZZ_HEADERS := fuzz_helpers.h fuzz.h +FUZZ_HEADERS := fuzz_helpers.h fuzz.h zstd_helpers.h +FUZZ_SRC := zstd_helpers.c -ZSTDCOMMON_FILES := $(ZSTDDIR)/common/*.c -ZSTDCOMP_FILES := $(ZSTDDIR)/compress/*.c -ZSTDDECOMP_FILES := $(ZSTDDIR)/decompress/*.c -ZSTD_FILES := $(ZSTDDECOMP_FILES) $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES) +ZSTDCOMMON_SRC := $(ZSTDDIR)/common/*.c +ZSTDCOMP_SRC := $(ZSTDDIR)/compress/*.c +ZSTDDECOMP_SRC := $(ZSTDDIR)/decompress/*.c +FUZZ_SRC := \ + $(FUZZ_SRC) \ + $(ZSTDDECOMP_SRC) \ + $(ZSTDCOMMON_SRC) \ + $(ZSTDCOMP_SRC) -ZSTD_OBJ := $(patsubst %.c,%.o, $(wildcard $(ZSTD_FILES))) +FUZZ_OBJ := $(patsubst %.c,%.o, $(wildcard $(FUZZ_SRC))) .PHONY: default all clean @@ -58,23 +63,23 @@ all: \ %.o: %.c $(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $^ -c -o $@ -simple_round_trip: $(FUZZ_HEADERS) $(ZSTD_OBJ) simple_round_trip.o - $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) simple_round_trip.o $(LIB_FUZZING_ENGINE) -o $@ +simple_round_trip: $(FUZZ_HEADERS) $(FUZZ_OBJ) simple_round_trip.o + $(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) simple_round_trip.o $(LIB_FUZZING_ENGINE) -o $@ -stream_round_trip: $(FUZZ_HEADERS) $(ZSTD_OBJ) stream_round_trip.o - $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) stream_round_trip.o $(LIB_FUZZING_ENGINE) -o $@ +stream_round_trip: $(FUZZ_HEADERS) $(FUZZ_OBJ) stream_round_trip.o + $(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) stream_round_trip.o $(LIB_FUZZING_ENGINE) -o $@ -block_round_trip: $(FUZZ_HEADERS) $(ZSTD_OBJ) block_round_trip.o - $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) block_round_trip.o $(LIB_FUZZING_ENGINE) -o $@ +block_round_trip: $(FUZZ_HEADERS) $(FUZZ_OBJ) block_round_trip.o + $(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) block_round_trip.o $(LIB_FUZZING_ENGINE) -o $@ -simple_decompress: $(FUZZ_HEADERS) $(ZSTD_OBJ) simple_decompress.o - $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) simple_decompress.o $(LIB_FUZZING_ENGINE) -o $@ +simple_decompress: $(FUZZ_HEADERS) $(FUZZ_OBJ) simple_decompress.o + $(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) simple_decompress.o $(LIB_FUZZING_ENGINE) -o $@ -stream_decompress: $(FUZZ_HEADERS) $(ZSTD_OBJ) stream_decompress.o - $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) stream_decompress.o $(LIB_FUZZING_ENGINE) -o $@ +stream_decompress: $(FUZZ_HEADERS) $(FUZZ_OBJ) stream_decompress.o + $(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) stream_decompress.o $(LIB_FUZZING_ENGINE) -o $@ -block_decompress: $(FUZZ_HEADERS) $(ZSTD_OBJ) block_decompress.o - $(CXX) $(FUZZ_TARGET_FLAGS) $(ZSTD_OBJ) block_decompress.o $(LIB_FUZZING_ENGINE) -o $@ +block_decompress: $(FUZZ_HEADERS) $(FUZZ_OBJ) block_decompress.o + $(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) block_decompress.o $(LIB_FUZZING_ENGINE) -o $@ libregression.a: $(FUZZ_HEADERS) $(PRGDIR)/util.h regression_driver.o $(AR) $(FUZZ_ARFLAGS) $@ regression_driver.o diff --git a/tests/fuzz/fuzz_helpers.h b/tests/fuzz/fuzz_helpers.h index cb3421bb8..468c39fb4 100644 --- a/tests/fuzz/fuzz_helpers.h +++ b/tests/fuzz/fuzz_helpers.h @@ -16,8 +16,10 @@ #include "fuzz.h" #include "xxhash.h" +#include "zstd.h" #include #include +#include #ifdef __cplusplus extern "C" { @@ -38,6 +40,8 @@ extern "C" { __LINE__, FUZZ_QUOTE(cond), (msg)), \ abort())) #define FUZZ_ASSERT(cond) FUZZ_ASSERT_MSG((cond), ""); +#define FUZZ_ZASSERT(code) \ + FUZZ_ASSERT_MSG(!ZSTD_isError(code), ZSTD_getErrorName(code)) #if defined(__GNUC__) #define FUZZ_STATIC static __inline __attribute__((unused)) @@ -55,23 +59,30 @@ extern "C" { * Consumes up to the first FUZZ_RNG_SEED_SIZE bytes of the input. */ FUZZ_STATIC uint32_t FUZZ_seed(uint8_t const **src, size_t* size) { - uint8_t const *data = *src; - size_t const toHash = MIN(FUZZ_RNG_SEED_SIZE, *size); - *size -= toHash; - *src += toHash; - return XXH32(data, toHash, 0); + uint8_t const *data = *src; + size_t const toHash = MIN(FUZZ_RNG_SEED_SIZE, *size); + *size -= toHash; + *src += toHash; + return XXH32(data, toHash, 0); } #define FUZZ_rotl32(x, r) (((x) << (r)) | ((x) >> (32 - (r)))) + FUZZ_STATIC uint32_t FUZZ_rand(uint32_t *state) { - static const uint32_t prime1 = 2654435761U; - static const uint32_t prime2 = 2246822519U; - uint32_t rand32 = *state; - rand32 *= prime1; - rand32 += prime2; - rand32 = FUZZ_rotl32(rand32, 13); - *state = rand32; - return rand32 >> 5; + static const uint32_t prime1 = 2654435761U; + static const uint32_t prime2 = 2246822519U; + uint32_t rand32 = *state; + rand32 *= prime1; + rand32 += prime2; + rand32 = FUZZ_rotl32(rand32, 13); + *state = rand32; + return rand32 >> 5; +} + +/* Returns a random numer in the range [min, max]. */ +FUZZ_STATIC uint32_t FUZZ_rand32(uint32_t *state, uint32_t min, uint32_t max) { + uint32_t random = FUZZ_rand(state); + return min + (random % (max - min + 1)); } #ifdef __cplusplus diff --git a/tests/fuzz/simple_round_trip.c b/tests/fuzz/simple_round_trip.c index 9df025283..f853485ad 100644 --- a/tests/fuzz/simple_round_trip.c +++ b/tests/fuzz/simple_round_trip.c @@ -12,12 +12,14 @@ * compares the result with the original, and calls abort() on corruption. */ +#define ZSTD_STATIC_LINKING_ONLY + #include #include #include #include #include "fuzz_helpers.h" -#include "zstd.h" +#include "zstd_helpers.h" static const int kMaxClevel = 19; @@ -32,14 +34,28 @@ static size_t roundTripTest(void *result, size_t resultCapacity, void *compressed, size_t compressedCapacity, const void *src, size_t srcSize) { - int const cLevel = FUZZ_rand(&seed) % kMaxClevel; - size_t const cSize = ZSTD_compressCCtx(cctx, compressed, compressedCapacity, - src, srcSize, cLevel); - if (ZSTD_isError(cSize)) { - fprintf(stderr, "Compression error: %s\n", ZSTD_getErrorName(cSize)); - return cSize; - } - return ZSTD_decompressDCtx(dctx, result, resultCapacity, compressed, cSize); + size_t cSize; + if (FUZZ_rand(&seed) & 1) { + ZSTD_inBuffer in = {src, srcSize, 0}; + ZSTD_outBuffer out = {compressed, compressedCapacity, 0}; + + ZSTD_CCtx_reset(cctx); + FUZZ_setRandomParameters(cctx, &seed); + size_t const err = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end); + if (err != 0) { + return err; + } + cSize = out.pos; + } else { + int const cLevel = FUZZ_rand(&seed) % kMaxClevel; + cSize = ZSTD_compressCCtx( + cctx, compressed, compressedCapacity, src, srcSize, cLevel); + } + if (ZSTD_isError(cSize)) { + fprintf(stderr, "Compression error: %s\n", ZSTD_getErrorName(cSize)); + return cSize; + } + return ZSTD_decompressDCtx(dctx, result, resultCapacity, compressed, cSize); } int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) diff --git a/tests/fuzz/stream_round_trip.c b/tests/fuzz/stream_round_trip.c index e796c1e7f..e3fdd3b8f 100644 --- a/tests/fuzz/stream_round_trip.c +++ b/tests/fuzz/stream_round_trip.c @@ -12,16 +12,16 @@ * compares the result with the original, and calls abort() on corruption. */ +#define ZSTD_STATIC_LINKING_ONLY + #include #include #include #include #include "fuzz_helpers.h" -#include "zstd.h" +#include "zstd_helpers.h" -static const int kMaxClevel = 19; - -static ZSTD_CStream *cstream = NULL; +ZSTD_CCtx *cctx = NULL; static ZSTD_DCtx *dctx = NULL; static uint8_t* cBuf = NULL; static uint8_t* rBuf = NULL; @@ -30,84 +30,89 @@ static uint32_t seed; static ZSTD_outBuffer makeOutBuffer(uint8_t *dst, size_t capacity) { - ZSTD_outBuffer buffer = { dst, 0, 0 }; + ZSTD_outBuffer buffer = { dst, 0, 0 }; - FUZZ_ASSERT(capacity > 0); - buffer.size = (FUZZ_rand(&seed) % capacity) + 1; - FUZZ_ASSERT(buffer.size <= capacity); + FUZZ_ASSERT(capacity > 0); + buffer.size = (FUZZ_rand(&seed) % capacity) + 1; + FUZZ_ASSERT(buffer.size <= capacity); - return buffer; + return buffer; } static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size) { - ZSTD_inBuffer buffer = { *src, 0, 0 }; + ZSTD_inBuffer buffer = { *src, 0, 0 }; - FUZZ_ASSERT(*size > 0); - buffer.size = (FUZZ_rand(&seed) % *size) + 1; - FUZZ_ASSERT(buffer.size <= *size); - *src += buffer.size; - *size -= buffer.size; + FUZZ_ASSERT(*size > 0); + buffer.size = (FUZZ_rand(&seed) % *size) + 1; + FUZZ_ASSERT(buffer.size <= *size); + *src += buffer.size; + *size -= buffer.size; - return buffer; + return buffer; } static size_t compress(uint8_t *dst, size_t capacity, const uint8_t *src, size_t srcSize) { - int cLevel = FUZZ_rand(&seed) % kMaxClevel; size_t dstSize = 0; - FUZZ_ASSERT(!ZSTD_isError(ZSTD_initCStream(cstream, cLevel))); + ZSTD_CCtx_reset(cctx); + FUZZ_setRandomParameters(cctx, &seed); while (srcSize > 0) { ZSTD_inBuffer in = makeInBuffer(&src, &srcSize); /* Mode controls the action. If mode == -1 we pick a new mode */ int mode = -1; while (in.pos < in.size) { - ZSTD_outBuffer out = makeOutBuffer(dst, capacity); - /* Previous action finished, pick a new mode. */ - if (mode == -1) mode = FUZZ_rand(&seed) % 10; - switch (mode) { - case 0: /* fall-though */ - case 1: /* fall-though */ - case 2: { - size_t const ret = ZSTD_flushStream(cstream, &out); - FUZZ_ASSERT_MSG(!ZSTD_isError(ret), ZSTD_getErrorName(ret)); - if (ret == 0) mode = -1; - break; - } - case 3: { - size_t ret = ZSTD_endStream(cstream, &out); - FUZZ_ASSERT_MSG(!ZSTD_isError(ret), ZSTD_getErrorName(ret)); - /* Reset the compressor when the frame is finished */ - if (ret == 0) { - cLevel = FUZZ_rand(&seed) % kMaxClevel; - ret = ZSTD_initCStream(cstream, cLevel); - FUZZ_ASSERT(!ZSTD_isError(ret)); + ZSTD_outBuffer out = makeOutBuffer(dst, capacity); + /* Previous action finished, pick a new mode. */ + if (mode == -1) mode = FUZZ_rand(&seed) % 10; + switch (mode) { + case 0: /* fall-though */ + case 1: /* fall-though */ + case 2: { + size_t const ret = + ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_flush); + FUZZ_ZASSERT(ret); + if (ret == 0) + mode = -1; + break; + } + case 3: { + size_t ret = + ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end); + FUZZ_ZASSERT(ret); + /* Reset the compressor when the frame is finished */ + if (ret == 0) { + ZSTD_CCtx_reset(cctx); + FUZZ_setRandomParameters(cctx, &seed); + mode = -1; + } + break; + } + default: { + size_t const ret = + ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_continue); + FUZZ_ZASSERT(ret); mode = -1; } - break; } - default: { - size_t const ret = ZSTD_compressStream(cstream, &out, &in); - FUZZ_ASSERT_MSG(!ZSTD_isError(ret), ZSTD_getErrorName(ret)); - mode = -1; - } - } - dst += out.pos; - dstSize += out.pos; - capacity -= out.pos; + dst += out.pos; + dstSize += out.pos; + capacity -= out.pos; } } for (;;) { + ZSTD_inBuffer in = {NULL, 0, 0}; ZSTD_outBuffer out = makeOutBuffer(dst, capacity); - size_t const ret = ZSTD_endStream(cstream, &out); - FUZZ_ASSERT_MSG(!ZSTD_isError(ret), ZSTD_getErrorName(ret)); + size_t const ret = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end); + FUZZ_ZASSERT(ret); dst += out.pos; dstSize += out.pos; capacity -= out.pos; - if (ret == 0) break; + if (ret == 0) + break; } return dstSize; } @@ -128,9 +133,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) bufSize = neededBufSize; FUZZ_ASSERT(cBuf && rBuf); } - if (!cstream) { - cstream = ZSTD_createCStream(); - FUZZ_ASSERT(cstream); + if (!cctx) { + cctx = ZSTD_createCCtx(); + FUZZ_ASSERT(cctx); } if (!dctx) { dctx = ZSTD_createDCtx(); @@ -147,7 +152,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) } #ifndef STATEFUL_FUZZING - ZSTD_freeCStream(cstream); cstream = NULL; + ZSTD_freeCCtx(cctx); cctx = NULL; ZSTD_freeDCtx(dctx); dctx = NULL; #endif return 0; diff --git a/tests/fuzz/zstd_helpers.c b/tests/fuzz/zstd_helpers.c new file mode 100644 index 000000000..c5bef0272 --- /dev/null +++ b/tests/fuzz/zstd_helpers.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016-present, 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). + */ + +#define ZSTD_STATIC_LINKING_ONLY + +#include "zstd_helpers.h" +#include "fuzz_helpers.h" +#include "zstd.h" + +static void setRand(ZSTD_CCtx *cctx, ZSTD_cParameter param, unsigned min, + unsigned max, uint32_t *state) { + unsigned const value = FUZZ_rand32(state, min, max); + FUZZ_ZASSERT(ZSTD_CCtx_setParameter(cctx, param, value)); +} + +void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, uint32_t *state) +{ + setRand(cctx, ZSTD_p_windowLog, ZSTD_WINDOWLOG_MIN, 23, state); + setRand(cctx, ZSTD_p_hashLog, ZSTD_HASHLOG_MIN, 23, state); + setRand(cctx, ZSTD_p_chainLog, ZSTD_CHAINLOG_MIN, 24, state); + setRand(cctx, ZSTD_p_searchLog, ZSTD_SEARCHLOG_MIN, 9, state); + setRand(cctx, ZSTD_p_minMatch, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX, + state); + setRand(cctx, ZSTD_p_targetLength, ZSTD_TARGETLENGTH_MIN, + ZSTD_TARGETLENGTH_MAX, state); + setRand(cctx, ZSTD_p_compressionStrategy, ZSTD_fast, ZSTD_btultra, state); + /* Select frame parameters */ + setRand(cctx, ZSTD_p_contentSizeFlag, 0, 1, state); + setRand(cctx, ZSTD_p_checksumFlag, 0, 1, state); + setRand(cctx, ZSTD_p_dictIDFlag, 0, 1, state); + /* Select long distance matchig parameters */ + setRand(cctx, ZSTD_p_enableLongDistanceMatching, 0, 1, state); + setRand(cctx, ZSTD_p_ldmHashLog, ZSTD_HASHLOG_MIN, 24, state); + setRand(cctx, ZSTD_p_ldmMinMatch, ZSTD_LDM_MINMATCH_MIN, + ZSTD_LDM_MINMATCH_MAX, state); + setRand(cctx, ZSTD_p_ldmBucketSizeLog, 0, ZSTD_LDM_BUCKETSIZELOG_MAX, + state); + setRand(cctx, ZSTD_p_ldmHashEveryLog, 0, + ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN, state); +} diff --git a/tests/fuzz/zstd_helpers.h b/tests/fuzz/zstd_helpers.h new file mode 100644 index 000000000..c2e3388a5 --- /dev/null +++ b/tests/fuzz/zstd_helpers.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016-present, 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). + */ + +/** + * Helper functions for fuzzing. + */ + +#ifndef ZSTD_HELPERS_H +#define ZSTD_HELPERS_H + +#include "zstd.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, uint32_t *state); + + +#ifdef __cplusplus +} +#endif + +#endif /* ZSTD_HELPERS_H */ From 77c137b3ae4d3c961952acf659b4fa515dffb1db Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 14 Sep 2017 15:12:57 -0700 Subject: [PATCH 141/248] minor comment refactor --- lib/dictBuilder/zdict.c | 6 +++--- programs/dibio.c | 48 ++++++++++++++++++++++------------------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/lib/dictBuilder/zdict.c b/lib/dictBuilder/zdict.c index b76e7695a..1bb8b0683 100644 --- a/lib/dictBuilder/zdict.c +++ b/lib/dictBuilder/zdict.c @@ -375,7 +375,7 @@ static int isIncluded(const void* in, const void* container, size_t length) return u==length; } -/*! ZDICT_checkMerge +/*! ZDICT_tryMerge() : check if dictItem can be merged, do it if possible @return : id of destination elt, 0 if not merged */ @@ -440,8 +440,8 @@ static U32 ZDICT_tryMerge(dictItem* table, dictItem elt, U32 eltNbToSkip, const static void ZDICT_removeDictItem(dictItem* table, U32 id) { - /* convention : first element is nb of elts */ - U32 const max = table->pos; + /* convention : table[0].pos stores nb of elts */ + U32 const max = table[0].pos; U32 u; if (!id) return; /* protection, should never happen */ for (u=id; u> 5; } +/* DiB_shuffle() : + * shuffle a table of file names in a semi-random way + * It improves dictionary quality by reducing "locality" impact, so if sample set is very large, + * it will load random elements from it, instead of just the first ones. */ static void DiB_shuffle(const char** fileNamesTable, unsigned nbFiles) { - /* Initialize the pseudorandom number generator */ - U32 seed = 0xFD2FB528; - unsigned i; - for (i = nbFiles - 1; i > 0; --i) { - unsigned const j = DiB_rand(&seed) % (i + 1); - const char* tmp = fileNamesTable[j]; - fileNamesTable[j] = fileNamesTable[i]; - fileNamesTable[i] = tmp; - } + U32 seed = 0xFD2FB528; + unsigned i; + for (i = nbFiles - 1; i > 0; --i) { + unsigned const j = DiB_rand(&seed) % (i + 1); + const char* const tmp = fileNamesTable[j]; + fileNamesTable[j] = fileNamesTable[i]; + fileNamesTable[i] = tmp; + } } @@ -162,7 +167,7 @@ static size_t DiB_findMaxMem(unsigned long long requiredMem) requiredMem = (((requiredMem >> 23) + 1) << 23); requiredMem += step; - if (requiredMem > maxMemory) requiredMem = maxMemory; + if (requiredMem > g_maxMemory) requiredMem = g_maxMemory; while (!testmem) { testmem = malloc((size_t)requiredMem); @@ -203,7 +208,7 @@ static void DiB_saveDict(const char* dictFileName, static int g_tooLargeSamples = 0; -static U64 DiB_getTotalCappedFileSize(const char** fileNamesTable, unsigned nbFiles) +static U64 DiB_totalCappedFileSize(const char** fileNamesTable, unsigned nbFiles) { U64 total = 0; unsigned n; @@ -236,7 +241,7 @@ int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, { void* const dictBuffer = malloc(maxDictSize); size_t* const fileSizes = (size_t*)malloc(nbFiles * sizeof(size_t)); - unsigned long long const totalSizeToLoad = DiB_getTotalCappedFileSize(fileNamesTable, nbFiles); + unsigned long long const totalSizeToLoad = DiB_totalCappedFileSize(fileNamesTable, nbFiles); size_t const memMult = params ? MEMMULT : COVER_MEMMULT; size_t const maxMem = DiB_findMaxMem(totalSizeToLoad * memMult) / memMult; size_t benchedSize = (size_t) MIN ((unsigned long long)maxMem, totalSizeToLoad); @@ -246,8 +251,9 @@ int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, /* Checks */ if (params) g_displayLevel = params->zParams.notificationLevel; else if (coverParams) g_displayLevel = coverParams->zParams.notificationLevel; - else EXM_THROW(13, "Neither dictionary algorith selected"); /* should not happen */ - if ((!fileSizes) || (!srcBuffer) || (!dictBuffer)) EXM_THROW(12, "not enough memory for DiB_trainFiles"); /* should not happen */ + else EXM_THROW(13, "Neither dictionary algorithm selected"); /* should not happen */ + if ((!fileSizes) || (!srcBuffer) || (!dictBuffer)) + EXM_THROW(12, "not enough memory for DiB_trainFiles"); /* should not happen */ if (g_tooLargeSamples) { DISPLAYLEVEL(2, "! Warning : some samples are very large \n"); DISPLAYLEVEL(2, "! Note that dictionary is only useful for small files or beginning of large files. \n"); @@ -270,8 +276,7 @@ int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, DiB_shuffle(fileNamesTable, nbFiles); nbFiles = DiB_loadFiles(srcBuffer, &benchedSize, fileSizes, fileNamesTable, nbFiles); - { - size_t dictSize; + { size_t dictSize; if (params) { DiB_fillNoise((char*)srcBuffer + benchedSize, NOISELENGTH); /* guard band, for end of buffer condition */ dictSize = ZDICT_trainFromBuffer_unsafe_legacy(dictBuffer, maxDictSize, @@ -285,9 +290,8 @@ int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, DISPLAYLEVEL(2, "k=%u\nd=%u\nsteps=%u\n", coverParams->k, coverParams->d, coverParams->steps); } } else { - dictSize = - ZDICT_trainFromBuffer_cover(dictBuffer, maxDictSize, srcBuffer, - fileSizes, nbFiles, *coverParams); + dictSize = ZDICT_trainFromBuffer_cover(dictBuffer, maxDictSize, srcBuffer, + fileSizes, nbFiles, *coverParams); } if (ZDICT_isError(dictSize)) { DISPLAYLEVEL(1, "dictionary training failed : %s \n", ZDICT_getErrorName(dictSize)); /* should not happen */ From 086b9597d9f53444fb43c6aa23db609078e7e5e9 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 14 Sep 2017 16:45:10 -0700 Subject: [PATCH 142/248] added ability to split input files for dictionary training using command -B# This is the same behavior as benchmark module, which can also split input into arbitrary size blocks, using -B#. --- doc/zstd_manual.html | 29 +++++++++ programs/dibio.c | 139 +++++++++++++++++++++++++------------------ programs/dibio.h | 2 +- programs/zstd.1.md | 4 +- programs/zstdcli.c | 4 +- 5 files changed, 116 insertions(+), 62 deletions(-) diff --git a/doc/zstd_manual.html b/doc/zstd_manual.html index 1c298726c..e7d861707 100644 --- a/doc/zstd_manual.html +++ b/doc/zstd_manual.html @@ -845,6 +845,35 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
    /* advanced parameters - may not remain available after API update */ ZSTD_p_forceMaxWindow=1100, /* Force back-reference distances to remain < windowSize, * even when referencing into Dictionary content (default:0) */ + ZSTD_p_enableLongDistanceMatching=1200, /* Enable long distance matching. + * This parameter is designed to improve the compression + * ratio for large inputs with long distance matches. + * This increases the memory usage as well as window size. + * Note: setting this parameter sets all the LDM parameters + * as well as ZSTD_p_windowLog. It should be set after + * ZSTD_p_compressionLevel and before ZSTD_p_windowLog and + * other LDM parameters. Setting the compression level + * after this parameter overrides the window log, though LDM + * will remain enabled until explicitly disabled. */ + ZSTD_p_ldmHashLog, /* Size of the table for long distance matching, as a power of 2. + * Larger values increase memory usage and compression ratio, but decrease + * compression speed. + * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX + * (default: 20). */ + ZSTD_p_ldmMinMatch, /* Minimum size of searched matches for long distance matcher. + * Larger/too small values usually decrease compression ratio. + * Must be clamped between ZSTD_LDM_MINMATCH_MIN + * and ZSTD_LDM_MINMATCH_MAX (default: 64). */ + ZSTD_p_ldmBucketSizeLog, /* Log size of each bucket in the LDM hash table for collision resolution. + * Larger values usually improve collision resolution but may decrease + * compression speed. + * The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX (default: 3). */ + ZSTD_p_ldmHashEveryLog, /* Frequency of inserting/looking up entries in the LDM hash table. + * The default is MAX(0, (windowLog - ldmHashLog)) to + * optimize hash table usage. + * Larger values improve compression speed. Deviating far from the + * default value will likely result in a decrease in compression ratio. + * Must be clamped between 0 and ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN. */ } ZSTD_cParameter;

    diff --git a/programs/dibio.c b/programs/dibio.c index 79f272912..d7b7601dc 100644 --- a/programs/dibio.c +++ b/programs/dibio.c @@ -53,13 +53,12 @@ static const size_t g_maxMemory = (sizeof(size_t) == 4) ? (2 GB - 64 MB) : ((siz * Console display ***************************************/ #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) -#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } -static int g_displayLevel = 0; /* 0 : no display; 1: errors; 2: default; 4: full information */ +#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); } -#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ - if ((DIB_clockSpan(g_time) > refreshRate) || (g_displayLevel>=4)) \ +#define DISPLAYUPDATE(l, ...) if (displayLevel>=l) { \ + if ((DIB_clockSpan(g_time) > refreshRate) || (displayLevel>=4)) \ { g_time = clock(); DISPLAY(__VA_ARGS__); \ - if (g_displayLevel>=4) fflush(stderr); } } + if (displayLevel>=4) fflush(stderr); } } static const clock_t refreshRate = CLOCKS_PER_SEC * 2 / 10; static clock_t g_time = 0; @@ -76,9 +75,9 @@ static clock_t DIB_clockSpan(clock_t nPrevious) { return clock() - nPrevious; } #define EXM_THROW(error, ...) \ { \ DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \ - DISPLAYLEVEL(1, "Error %i : ", error); \ - DISPLAYLEVEL(1, __VA_ARGS__); \ - DISPLAYLEVEL(1, "\n"); \ + DISPLAY("Error %i : ", error); \ + DISPLAY(__VA_ARGS__); \ + DISPLAY("\n"); \ exit(error); \ } @@ -102,30 +101,42 @@ const char* DiB_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCo * @return : nb of files effectively loaded into `buffer` * *bufferSizePtr is modified, it provides the amount data loaded within buffer */ static unsigned DiB_loadFiles(void* buffer, size_t* bufferSizePtr, - size_t* fileSizes, - const char** fileNamesTable, unsigned nbFiles) + size_t* chunkSizes, + const char** fileNamesTable, unsigned nbFiles, size_t targetChunkSize, + unsigned displayLevel) { char* const buff = (char*)buffer; size_t pos = 0; - unsigned n; + unsigned nbLoadedChunks = 0, fileIndex; - for (n=0; n *bufferSizePtr-pos) break; - { FILE* const f = fopen(fileName, "rb"); - if (f==NULL) EXM_THROW(10, "zstd: dictBuilder: %s %s ", fileName, strerror(errno)); - DISPLAYUPDATE(2, "Loading %s... \r", fileName); - { size_t const readSize = fread(buff+pos, 1, fileSize, f); - if (readSize != fileSize) EXM_THROW(11, "Pb reading %s", fileName); - pos += readSize; } - fileSizes[n] = fileSize; - fclose(f); - } } + unsigned long long remainingToLoad = fs64; + U32 const nbChunks = targetChunkSize ? (U32)((fs64 + (targetChunkSize-1)) / targetChunkSize) : 1; + U64 const chunkSize = targetChunkSize ? MIN(targetChunkSize, fs64) : fs64; + size_t const maxChunkSize = MIN(chunkSize, SAMPLESIZE_MAX); + U32 cnb; + FILE* const f = fopen(fileName, "rb"); + if (f==NULL) EXM_THROW(10, "zstd: dictBuilder: %s %s ", fileName, strerror(errno)); + DISPLAYUPDATE(2, "Loading %s... \r", fileName); + for (cnb=0; cnb *bufferSizePtr-pos) break; + { size_t const readSize = fread(buff+pos, 1, toLoad, f); + if (readSize != toLoad) EXM_THROW(11, "Pb reading %s", fileName); + pos += readSize; + chunkSizes[nbLoadedChunks++] = toLoad; + remainingToLoad -= targetChunkSize; + if (toLoad < targetChunkSize) { + fseek(f, (targetChunkSize - toLoad), SEEK_CUR); + } } } + fclose(f); + } DISPLAYLEVEL(2, "\r%79s\r", ""); *bufferSizePtr = pos; - return n; + DISPLAYLEVEL(4, "loaded : %u KB \n", (U32)(pos >> 10)) + return nbLoadedChunks; } #define DiB_rotl32(x,r) ((x << r) | (x >> (32 - r))) @@ -207,18 +218,28 @@ static void DiB_saveDict(const char* dictFileName, } -static int g_tooLargeSamples = 0; -static U64 DiB_totalCappedFileSize(const char** fileNamesTable, unsigned nbFiles) +typedef struct { + U64 totalSizeToLoad; + unsigned oneSampleTooLarge; + unsigned nbChunks; +} fileStats; + +static fileStats DiB_fileStats(const char** fileNamesTable, unsigned nbFiles, size_t chunkSize, unsigned displayLevel) { - U64 total = 0; + fileStats fs; unsigned n; + memset(&fs, 0, sizeof(fs)); for (n=0; n 2*SAMPLESIZE_MAX); + U32 const nbChunks = (U32)(chunkSize ? (fileSize + (chunkSize-1)) / chunkSize : 1); + U64 const chunkToLoad = chunkSize ? MIN(chunkSize, fileSize) : fileSize; + size_t const cappedChunkSize = MIN(chunkToLoad, SAMPLESIZE_MAX); + fs.totalSizeToLoad += cappedChunkSize * nbChunks; + fs.oneSampleTooLarge |= (chunkSize > 2*SAMPLESIZE_MAX); + fs.nbChunks += nbChunks; } - return total; + DISPLAYLEVEL(4, "Preparing to load : %u KB \n", (U32)(fs.totalSizeToLoad >> 10)); + return fs; } @@ -235,63 +256,65 @@ size_t ZDICT_trainFromBuffer_unsafe_legacy(void* dictBuffer, size_t dictBufferCa int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, - const char** fileNamesTable, unsigned nbFiles, + const char** fileNamesTable, unsigned nbFiles, size_t chunkSize, ZDICT_legacy_params_t *params, ZDICT_cover_params_t *coverParams, int optimizeCover) { + unsigned displayLevel = params ? params->zParams.notificationLevel : + coverParams ? coverParams->zParams.notificationLevel : + 0; /* should never happen */ void* const dictBuffer = malloc(maxDictSize); - size_t* const fileSizes = (size_t*)malloc(nbFiles * sizeof(size_t)); - unsigned long long const totalSizeToLoad = DiB_totalCappedFileSize(fileNamesTable, nbFiles); + fileStats const fs = DiB_fileStats(fileNamesTable, nbFiles, chunkSize, displayLevel); + size_t* const chunkSizes = (size_t*)malloc(fs.nbChunks * sizeof(size_t)); size_t const memMult = params ? MEMMULT : COVER_MEMMULT; - size_t const maxMem = DiB_findMaxMem(totalSizeToLoad * memMult) / memMult; - size_t benchedSize = (size_t) MIN ((unsigned long long)maxMem, totalSizeToLoad); - void* const srcBuffer = malloc(benchedSize+NOISELENGTH); + size_t const maxMem = DiB_findMaxMem(fs.totalSizeToLoad * memMult) / memMult; + size_t loadedSize = (size_t) MIN ((unsigned long long)maxMem, fs.totalSizeToLoad); + void* const srcBuffer = malloc(loadedSize+NOISELENGTH); int result = 0; /* Checks */ - if (params) g_displayLevel = params->zParams.notificationLevel; - else if (coverParams) g_displayLevel = coverParams->zParams.notificationLevel; - else EXM_THROW(13, "Neither dictionary algorithm selected"); /* should not happen */ - if ((!fileSizes) || (!srcBuffer) || (!dictBuffer)) + if ((!chunkSizes) || (!srcBuffer) || (!dictBuffer)) EXM_THROW(12, "not enough memory for DiB_trainFiles"); /* should not happen */ - if (g_tooLargeSamples) { - DISPLAYLEVEL(2, "! Warning : some samples are very large \n"); - DISPLAYLEVEL(2, "! Note that dictionary is only useful for small files or beginning of large files. \n"); - DISPLAYLEVEL(2, "! As a consequence, only the first %u bytes of each file are loaded \n", SAMPLESIZE_MAX); + if (fs.oneSampleTooLarge) { + DISPLAYLEVEL(2, "! Warning : some sample(s) are very large \n"); + DISPLAYLEVEL(2, "! Note that dictionary is only useful for small samples. \n"); + DISPLAYLEVEL(2, "! As a consequence, only the first %u bytes of each sample are loaded \n", SAMPLESIZE_MAX); } - if ((nbFiles < 5) || (totalSizeToLoad < 9 * (unsigned long long)maxDictSize)) { + if (fs.nbChunks < 5) { DISPLAYLEVEL(2, "! Warning : nb of samples too low for proper processing ! \n"); DISPLAYLEVEL(2, "! Please provide _one file per sample_. \n"); - DISPLAYLEVEL(2, "! Do not concatenate samples together into a single file, \n"); - DISPLAYLEVEL(2, "! as dictBuilder will be unable to find the beginning of each sample, \n"); - DISPLAYLEVEL(2, "! resulting in poor dictionary quality. \n"); + EXM_THROW(14, "nb of samples too low"); /* we now clearly forbid this case */ + } + if (fs.totalSizeToLoad < (unsigned long long)(8 * maxDictSize)) { + DISPLAYLEVEL(2, "! Warning : data size of samples too small for target dictionary size \n"); + DISPLAYLEVEL(2, "! Samples should be about 100x larger than target dictionary size \n"); } /* init */ - if (benchedSize < totalSizeToLoad) - DISPLAYLEVEL(1, "Not enough memory; training on %u MB only...\n", (unsigned)(benchedSize >> 20)); + if (loadedSize < fs.totalSizeToLoad) + DISPLAYLEVEL(1, "Not enough memory; training on %u MB only...\n", (unsigned)(loadedSize >> 20)); /* Load input buffer */ DISPLAYLEVEL(3, "Shuffling input files\n"); DiB_shuffle(fileNamesTable, nbFiles); - nbFiles = DiB_loadFiles(srcBuffer, &benchedSize, fileSizes, fileNamesTable, nbFiles); + nbFiles = DiB_loadFiles(srcBuffer, &loadedSize, chunkSizes, fileNamesTable, nbFiles, chunkSize, displayLevel); { size_t dictSize; if (params) { - DiB_fillNoise((char*)srcBuffer + benchedSize, NOISELENGTH); /* guard band, for end of buffer condition */ + DiB_fillNoise((char*)srcBuffer + loadedSize, NOISELENGTH); /* guard band, for end of buffer condition */ dictSize = ZDICT_trainFromBuffer_unsafe_legacy(dictBuffer, maxDictSize, - srcBuffer, fileSizes, nbFiles, + srcBuffer, chunkSizes, fs.nbChunks, *params); } else if (optimizeCover) { dictSize = ZDICT_optimizeTrainFromBuffer_cover(dictBuffer, maxDictSize, - srcBuffer, fileSizes, nbFiles, + srcBuffer, chunkSizes, fs.nbChunks, coverParams); if (!ZDICT_isError(dictSize)) { DISPLAYLEVEL(2, "k=%u\nd=%u\nsteps=%u\n", coverParams->k, coverParams->d, coverParams->steps); } } else { dictSize = ZDICT_trainFromBuffer_cover(dictBuffer, maxDictSize, srcBuffer, - fileSizes, nbFiles, *coverParams); + chunkSizes, fs.nbChunks, *coverParams); } if (ZDICT_isError(dictSize)) { DISPLAYLEVEL(1, "dictionary training failed : %s \n", ZDICT_getErrorName(dictSize)); /* should not happen */ @@ -306,7 +329,7 @@ int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, /* clean up */ _cleanup: free(srcBuffer); + free(chunkSizes); free(dictBuffer); - free(fileSizes); return result; } diff --git a/programs/dibio.h b/programs/dibio.h index ac2424491..499e30365 100644 --- a/programs/dibio.h +++ b/programs/dibio.h @@ -32,7 +32,7 @@ @return : 0 == ok. Any other : error. */ int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, - const char** fileNamesTable, unsigned nbFiles, + const char** fileNamesTable, unsigned nbFiles, size_t chunkSize, ZDICT_legacy_params_t *params, ZDICT_cover_params_t *coverParams, int optimizeCover); diff --git a/programs/zstd.1.md b/programs/zstd.1.md index 2fcedde3c..e446422b6 100644 --- a/programs/zstd.1.md +++ b/programs/zstd.1.md @@ -184,6 +184,8 @@ Typical gains range from 10% (at 64KB) to x5 better (at <1KB). Dictionary saved into `file` (default name: dictionary). * `--maxdict=#`: Limit dictionary to specified size (default: 112640). +* `-B#`: + Split input files in blocks of size # (default: no split) * `--dictID=#`: A dictionary ID is a locally unique ID that a decoder can use to verify it is using the right dictionary. @@ -373,7 +375,7 @@ The list of available _options_: default value will likely result in a decrease in compression ratio. The default value is `wlog - ldmhlog`. - + ### -B#: Select the size of each compression job. This parameter is available only when multi-threading is enabled. diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 607287c91..78adcb6cd 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -759,13 +759,13 @@ int main(int argCount, const char* argv[]) int const optimize = !coverParams.k || !coverParams.d; coverParams.nbThreads = nbThreads; coverParams.zParams = zParams; - operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, NULL, &coverParams, optimize); + operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, blockSize, NULL, &coverParams, optimize); } else { ZDICT_legacy_params_t dictParams; memset(&dictParams, 0, sizeof(dictParams)); dictParams.selectivityLevel = dictSelect; dictParams.zParams = zParams; - operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, &dictParams, NULL, 0); + operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, blockSize, &dictParams, NULL, 0); } #endif goto _end; From a9694231ca4ebf2391b2100675d0d7a2639680d9 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 15 Sep 2017 10:16:26 -0700 Subject: [PATCH 143/248] fixed minor conversion warning --- programs/dibio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/dibio.c b/programs/dibio.c index d7b7601dc..5ea384c6b 100644 --- a/programs/dibio.c +++ b/programs/dibio.c @@ -129,7 +129,7 @@ static unsigned DiB_loadFiles(void* buffer, size_t* bufferSizePtr, chunkSizes[nbLoadedChunks++] = toLoad; remainingToLoad -= targetChunkSize; if (toLoad < targetChunkSize) { - fseek(f, (targetChunkSize - toLoad), SEEK_CUR); + fseek(f, (long)(targetChunkSize - toLoad), SEEK_CUR); } } } fclose(f); } From 25a60488dd3371881058f401185a61436373de1d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 15 Sep 2017 11:55:13 -0700 Subject: [PATCH 144/248] fixed 64-to-32 conversion warnings --- programs/dibio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/programs/dibio.c b/programs/dibio.c index 5ea384c6b..6e86e8463 100644 --- a/programs/dibio.c +++ b/programs/dibio.c @@ -115,13 +115,13 @@ static unsigned DiB_loadFiles(void* buffer, size_t* bufferSizePtr, unsigned long long remainingToLoad = fs64; U32 const nbChunks = targetChunkSize ? (U32)((fs64 + (targetChunkSize-1)) / targetChunkSize) : 1; U64 const chunkSize = targetChunkSize ? MIN(targetChunkSize, fs64) : fs64; - size_t const maxChunkSize = MIN(chunkSize, SAMPLESIZE_MAX); + size_t const maxChunkSize = (size_t)MIN(chunkSize, SAMPLESIZE_MAX); U32 cnb; FILE* const f = fopen(fileName, "rb"); if (f==NULL) EXM_THROW(10, "zstd: dictBuilder: %s %s ", fileName, strerror(errno)); DISPLAYUPDATE(2, "Loading %s... \r", fileName); for (cnb=0; cnb *bufferSizePtr-pos) break; { size_t const readSize = fread(buff+pos, 1, toLoad, f); if (readSize != toLoad) EXM_THROW(11, "Pb reading %s", fileName); @@ -233,7 +233,7 @@ static fileStats DiB_fileStats(const char** fileNamesTable, unsigned nbFiles, si U64 const fileSize = UTIL_getFileSize(fileNamesTable[n]); U32 const nbChunks = (U32)(chunkSize ? (fileSize + (chunkSize-1)) / chunkSize : 1); U64 const chunkToLoad = chunkSize ? MIN(chunkSize, fileSize) : fileSize; - size_t const cappedChunkSize = MIN(chunkToLoad, SAMPLESIZE_MAX); + size_t const cappedChunkSize = (size_t)MIN(chunkToLoad, SAMPLESIZE_MAX); fs.totalSizeToLoad += cappedChunkSize * nbChunks; fs.oneSampleTooLarge |= (chunkSize > 2*SAMPLESIZE_MAX); fs.nbChunks += nbChunks; From c68d17f2da0af7c3c98bcebb0187ff344a2a817f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 15 Sep 2017 15:31:31 -0700 Subject: [PATCH 145/248] ensures that sampleSizes table is large enough as recommended by @terrelln --- programs/dibio.c | 54 ++++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/programs/dibio.c b/programs/dibio.c index 6e86e8463..66f7d1526 100644 --- a/programs/dibio.c +++ b/programs/dibio.c @@ -97,11 +97,16 @@ const char* DiB_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCo * File related operations **********************************************************/ /** DiB_loadFiles() : - * load files listed in fileNamesTable into buffer, even if buffer is too small. - * @return : nb of files effectively loaded into `buffer` - * *bufferSizePtr is modified, it provides the amount data loaded within buffer */ + * load samples from files listed in fileNamesTable into buffer. + * works even if buffer is too small to load all samples. + * Also provides the size of each sample into sampleSizes table + * which must be sized correctly, using DiB_fileStats(). + * @return : nb of samples effectively loaded into `buffer` + * *bufferSizePtr is modified, it provides the amount data loaded within buffer. + * sampleSizes is filled with the size of each sample. + */ static unsigned DiB_loadFiles(void* buffer, size_t* bufferSizePtr, - size_t* chunkSizes, + size_t* sampleSizes, unsigned sstSize, const char** fileNamesTable, unsigned nbFiles, size_t targetChunkSize, unsigned displayLevel) { @@ -126,8 +131,12 @@ static unsigned DiB_loadFiles(void* buffer, size_t* bufferSizePtr, { size_t const readSize = fread(buff+pos, 1, toLoad, f); if (readSize != toLoad) EXM_THROW(11, "Pb reading %s", fileName); pos += readSize; - chunkSizes[nbLoadedChunks++] = toLoad; + sampleSizes[nbLoadedChunks++] = toLoad; remainingToLoad -= targetChunkSize; + if (nbLoadedChunks == sstSize) { /* no more space left in sampleSizes table */ + fileIndex = nbFiles; /* stop there */ + break; + } if (toLoad < targetChunkSize) { fseek(f, (long)(targetChunkSize - toLoad), SEEK_CUR); } } } @@ -221,9 +230,14 @@ static void DiB_saveDict(const char* dictFileName, typedef struct { U64 totalSizeToLoad; unsigned oneSampleTooLarge; - unsigned nbChunks; + unsigned nbSamples; } fileStats; +/*! DiB_fileStats() : + * Given a list of files, and a chunkSize (0 == no chunk, whole files) + * provides the amount of data to be loaded and the resulting nb of samples. + * This is useful primarily for allocation purpose => sample buffer, and sample sizes table. + */ static fileStats DiB_fileStats(const char** fileNamesTable, unsigned nbFiles, size_t chunkSize, unsigned displayLevel) { fileStats fs; @@ -231,12 +245,12 @@ static fileStats DiB_fileStats(const char** fileNamesTable, unsigned nbFiles, si memset(&fs, 0, sizeof(fs)); for (n=0; n 2*SAMPLESIZE_MAX); - fs.nbChunks += nbChunks; + fs.nbSamples += nbSamples; } DISPLAYLEVEL(4, "Preparing to load : %u KB \n", (U32)(fs.totalSizeToLoad >> 10)); return fs; @@ -260,12 +274,12 @@ int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, ZDICT_legacy_params_t *params, ZDICT_cover_params_t *coverParams, int optimizeCover) { - unsigned displayLevel = params ? params->zParams.notificationLevel : - coverParams ? coverParams->zParams.notificationLevel : - 0; /* should never happen */ + unsigned const displayLevel = params ? params->zParams.notificationLevel : + coverParams ? coverParams->zParams.notificationLevel : + 0; /* should never happen */ void* const dictBuffer = malloc(maxDictSize); fileStats const fs = DiB_fileStats(fileNamesTable, nbFiles, chunkSize, displayLevel); - size_t* const chunkSizes = (size_t*)malloc(fs.nbChunks * sizeof(size_t)); + size_t* const sampleSizes = (size_t*)malloc(fs.nbSamples * sizeof(size_t)); size_t const memMult = params ? MEMMULT : COVER_MEMMULT; size_t const maxMem = DiB_findMaxMem(fs.totalSizeToLoad * memMult) / memMult; size_t loadedSize = (size_t) MIN ((unsigned long long)maxMem, fs.totalSizeToLoad); @@ -273,14 +287,14 @@ int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, int result = 0; /* Checks */ - if ((!chunkSizes) || (!srcBuffer) || (!dictBuffer)) + if ((!sampleSizes) || (!srcBuffer) || (!dictBuffer)) EXM_THROW(12, "not enough memory for DiB_trainFiles"); /* should not happen */ if (fs.oneSampleTooLarge) { DISPLAYLEVEL(2, "! Warning : some sample(s) are very large \n"); DISPLAYLEVEL(2, "! Note that dictionary is only useful for small samples. \n"); DISPLAYLEVEL(2, "! As a consequence, only the first %u bytes of each sample are loaded \n", SAMPLESIZE_MAX); } - if (fs.nbChunks < 5) { + if (fs.nbSamples < 5) { DISPLAYLEVEL(2, "! Warning : nb of samples too low for proper processing ! \n"); DISPLAYLEVEL(2, "! Please provide _one file per sample_. \n"); EXM_THROW(14, "nb of samples too low"); /* we now clearly forbid this case */ @@ -297,24 +311,24 @@ int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, /* Load input buffer */ DISPLAYLEVEL(3, "Shuffling input files\n"); DiB_shuffle(fileNamesTable, nbFiles); - nbFiles = DiB_loadFiles(srcBuffer, &loadedSize, chunkSizes, fileNamesTable, nbFiles, chunkSize, displayLevel); + nbFiles = DiB_loadFiles(srcBuffer, &loadedSize, sampleSizes, fs.nbSamples, fileNamesTable, nbFiles, chunkSize, displayLevel); { size_t dictSize; if (params) { DiB_fillNoise((char*)srcBuffer + loadedSize, NOISELENGTH); /* guard band, for end of buffer condition */ dictSize = ZDICT_trainFromBuffer_unsafe_legacy(dictBuffer, maxDictSize, - srcBuffer, chunkSizes, fs.nbChunks, + srcBuffer, sampleSizes, fs.nbSamples, *params); } else if (optimizeCover) { dictSize = ZDICT_optimizeTrainFromBuffer_cover(dictBuffer, maxDictSize, - srcBuffer, chunkSizes, fs.nbChunks, + srcBuffer, sampleSizes, fs.nbSamples, coverParams); if (!ZDICT_isError(dictSize)) { DISPLAYLEVEL(2, "k=%u\nd=%u\nsteps=%u\n", coverParams->k, coverParams->d, coverParams->steps); } } else { dictSize = ZDICT_trainFromBuffer_cover(dictBuffer, maxDictSize, srcBuffer, - chunkSizes, fs.nbChunks, *coverParams); + sampleSizes, fs.nbSamples, *coverParams); } if (ZDICT_isError(dictSize)) { DISPLAYLEVEL(1, "dictionary training failed : %s \n", ZDICT_getErrorName(dictSize)); /* should not happen */ @@ -329,7 +343,7 @@ int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, /* clean up */ _cleanup: free(srcBuffer); - free(chunkSizes); + free(sampleSizes); free(dictBuffer); return result; } From 172205579918c485e56daddd7a457935dfcb1a05 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 15 Sep 2017 16:23:50 -0700 Subject: [PATCH 146/248] add comment on using -B# to split input file for dictionary training --- programs/dibio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/dibio.c b/programs/dibio.c index 66f7d1526..2cb2a4267 100644 --- a/programs/dibio.c +++ b/programs/dibio.c @@ -297,6 +297,7 @@ int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, if (fs.nbSamples < 5) { DISPLAYLEVEL(2, "! Warning : nb of samples too low for proper processing ! \n"); DISPLAYLEVEL(2, "! Please provide _one file per sample_. \n"); + DISPLAYLEVEL(2, "! Alternatively, split files into fixed-size blocks representative of samples, with -B# \n"); EXM_THROW(14, "nb of samples too low"); /* we now clearly forbid this case */ } if (fs.totalSizeToLoad < (unsigned long long)(8 * maxDictSize)) { From 5f2247951704c1f1c3a34b572499eb0bc22858ce Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 15 Sep 2017 17:22:38 -0700 Subject: [PATCH 147/248] [block] Don't use fParams in ZSTD_decompressBlock() --- lib/decompress/zstd_decompress.c | 54 +++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index aa4c58d91..6d6d83396 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -860,7 +860,10 @@ size_t ZSTD_execSequenceLast7(BYTE* op, } -static seq_t ZSTD_decodeSequence(seqState_t* seqState) +typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e; + + +static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets) { seq_t seq; @@ -900,8 +903,16 @@ static seq_t ZSTD_decodeSequence(seqState_t* seqState) if (!ofCode) offset = 0; else { - offset = OF_base[ofCode] + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ - if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); + ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); + if (longOffsets) { + int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN); + offset = OF_base[ofCode] + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); + if (MEM_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream); + if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits); + } else { + offset = OF_base[ofCode] + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); + } } if (ofCode <= 1) { @@ -1030,7 +1041,8 @@ size_t ZSTD_execSequence(BYTE* op, static size_t ZSTD_decompressSequences( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, - const void* seqStart, size_t seqSize) + const void* seqStart, size_t seqSize, + const ZSTD_longOffset_e isLongOffset) { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; @@ -1065,7 +1077,7 @@ static size_t ZSTD_decompressSequences( for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; ) { nbSeq--; - { seq_t const sequence = ZSTD_decodeSequence(&seqState); + { seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset); size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, base, vBase, dictEnd); DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); if (ZSTD_isError(oneSeqSize)) return oneSeqSize; @@ -1090,7 +1102,6 @@ static size_t ZSTD_decompressSequences( } -typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e; HINT_INLINE seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const longOffsets) @@ -1133,6 +1144,7 @@ seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const long if (!ofCode) offset = 0; else { + ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); if (longOffsets) { int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN); offset = OF_base[ofCode] + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); @@ -1268,7 +1280,8 @@ size_t ZSTD_execSequenceLong(BYTE* op, static size_t ZSTD_decompressSequencesLong( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, - const void* seqStart, size_t seqSize) + const void* seqStart, size_t seqSize, + const ZSTD_longOffset_e isLongOffset) { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; @@ -1282,10 +1295,6 @@ static size_t ZSTD_decompressSequencesLong( const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); int nbSeq; - unsigned long long const regularWindowSizeMax = 1ULL << STREAM_ACCUMULATOR_MIN; - ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (dctx->fParams.windowSize >= regularWindowSizeMax)); - ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); - /* Build Decoding Tables */ { size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, seqSize); if (ZSTD_isError(seqHSize)) return seqHSize; @@ -1353,9 +1362,18 @@ static size_t ZSTD_decompressSequencesLong( static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, - const void* src, size_t srcSize) + const void* src, size_t srcSize, const int frame) { /* blockType == blockCompressed */ const BYTE* ip = (const BYTE*)src; + /* isLongOffset must be true if there are long offsets. + * Offsets are long if they are larger than 2^STREAM_ACCUMULATOR_MIN. + * We don't expect that to be the case in 64-bit mode. + * If we are in block mode we don't know the window size, so we have to be + * conservative. + */ + ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN))); + /* We don't expect window sizes this big. */ + assert(!frame || dctx->fParams.windowSize <= (1ULL << STREAM_ACCUMULATOR_MIN_64)); DEBUGLOG(5, "ZSTD_decompressBlock_internal"); if (srcSize >= ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); @@ -1367,9 +1385,9 @@ static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, ip += litCSize; srcSize -= litCSize; } - if (dctx->fParams.windowSize > (1<<23)) - return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize); - return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize); + if (frame && dctx->fParams.windowSize > (1<<23)) + return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, isLongOffset); + return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, isLongOffset); } @@ -1389,7 +1407,7 @@ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, { size_t dSize; ZSTD_checkContinuity(dctx, dst); - dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize); + dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0); dctx->previousDstEnd = (char*)dst + dSize; return dSize; } @@ -1505,7 +1523,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, switch(blockProperties.blockType) { case bt_compressed: - decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize); + decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize, /* frame */ 1); break; case bt_raw : decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize); @@ -1759,7 +1777,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c { case bt_compressed: DEBUGLOG(5, "case bt_compressed"); - rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize); + rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1); break; case bt_raw : rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize); From 539b91ee9b6645ee5bfb2fb8ecd6c1bc864d606c Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 16 Sep 2017 23:40:14 -0700 Subject: [PATCH 148/248] minor : added assert in bt --- lib/compress/zstd_lazy.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c index b4fec514b..2a7f6a0fe 100644 --- a/lib/compress/zstd_lazy.c +++ b/lib/compress/zstd_lazy.c @@ -49,6 +49,7 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co predictedLarge += (predictedLarge>0); #endif /* ZSTD_C_PREDICT */ + assert(ip <= iend-8); /* required for h calculation */ hashTable[h] = current; /* Update Hash Table */ while (nbCompares-- && (matchIndex > windowLow)) { @@ -93,27 +94,27 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co } if (ip+matchLength == iend) /* equal : no way to know if inf or sup */ - break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */ + break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */ - if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */ - /* match is smaller than current */ + if (match[matchLength] < ip[matchLength]) { /* necessarily within buffer */ + /* match+1 is smaller than current */ *smallerPtr = matchIndex; /* update smaller idx */ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */ - if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */ + if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */ smallerPtr = nextPtr+1; /* new "smaller" => larger of match */ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */ } else { /* match is larger than current */ *largerPtr = matchIndex; commonLengthLarger = matchLength; - if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */ + if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */ largerPtr = nextPtr; matchIndex = nextPtr[0]; } } *smallerPtr = *largerPtr = 0; if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */ - if (matchEndIdx > current + 8) return matchEndIdx - current - 8; + if (matchEndIdx > current + 8) return matchEndIdx - (current + 8); return 1; } @@ -147,6 +148,7 @@ static size_t ZSTD_insertBtAndFindBestMatch ( U32 dummy32; /* to be nullified at the end */ size_t bestLength = 0; + assert(ip <= iend-8); /* required for h calculation */ hashTable[h] = current; /* Update Hash Table */ while (nbCompares-- && (matchIndex > windowLow)) { From 92889709f9805b8a6e166b4d0e080abefcf01632 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 18 Sep 2017 13:41:54 -0700 Subject: [PATCH 149/248] fix #851 : sudo zstd -t file.zst changes /dev/null permissions reported by @mike155 --- NEWS | 6 +++++- programs/fileio.c | 26 ++++++++++++++------------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/NEWS b/NEWS index 1300c80d4..bb7eaaca8 100644 --- a/NEWS +++ b/NEWS @@ -1,8 +1,12 @@ v1.3.2 +new : long range mode, using --long command, by Stella Lau (@stellamplau) license : changed /examples license to BSD + GPLv2 license : fix a few header files to reflect new license (#825) -fix : 32-bits build can now decode large offsets (levels 21+) +fix : multi-threading compression works with custom allocators fix : a rare compression bug when compression generates very large distances (only possible at --ultra -22) +fix : 32-bits build can now decode large offsets (levels 21+) +cli : new : can split input file for dictionary training, using command -B# +cli : fix : do not change /dev/null permissions when using command -t with root access, reported by @mike155 (#851) build: fix : no-multithread variant compiles without pool.c dependency, reported by Mitchell Blank Jr (@mitchblank) (#819) build: better compatibility with reproducible builds, by Bernhard M. Wiedemann (@bmwiedemann) (#818) diff --git a/programs/fileio.c b/programs/fileio.c index cef3f2c9e..623c4f4df 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -105,9 +105,6 @@ static clock_t g_time = 0; #define MIN(a,b) ((a) < (b) ? (a) : (b)) -/*-************************************* -* Errors -***************************************/ /*-************************************* * Debug ***************************************/ @@ -1023,8 +1020,8 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile ***************************************************************************/ typedef struct { void* srcBuffer; - size_t srcBufferLoaded; size_t srcBufferSize; + size_t srcBufferLoaded; void* dstBuffer; size_t dstBufferSize; ZSTD_DStream* dctx; @@ -1560,11 +1557,11 @@ static int FIO_decompressSrcFile(dRess_t ress, const char* dstFileName, const ch /* Close file */ if (fclose(srcFile)) { - DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno)); /* error should never happen */ + DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno)); /* error should not happen */ return 1; } if ( g_removeSrcFile /* --rm */ - && (result==0) /* decompression successful */ + && (result==0) /* decompression successful */ && strcmp(srcFileName, stdinmark) ) /* not stdin */ { if (remove(srcFileName)) { /* failed to remove src file */ @@ -1590,7 +1587,8 @@ static int FIO_decompressDstFile(dRess_t ress, ress.dstFile = FIO_openDstFile(dstFileName); if (ress.dstFile==0) return 1; - if (strcmp (srcFileName, stdinmark) && UTIL_getFileStat(srcFileName, &statbuf)) + if ( strcmp(srcFileName, stdinmark) + && UTIL_getFileStat(srcFileName, &statbuf) ) stat_result = 1; result = FIO_decompressSrcFile(ress, dstFileName, srcFileName); @@ -1600,11 +1598,15 @@ static int FIO_decompressDstFile(dRess_t ress, } if ( (result != 0) /* operation failure */ - && strcmp(dstFileName, nulmark) /* special case : don't remove() /dev/null (#316) */ - && remove(dstFileName) /* remove artefact */ ) - result=1; /* don't do anything special if remove() fails */ - else if (strcmp (dstFileName, stdoutmark) && stat_result) - UTIL_setFileStat(dstFileName, &statbuf); + && strcmp(dstFileName, nulmark) /* special case : don't remove() /dev/null (#316) */ + && strcmp(dstFileName, stdoutmark) ) /* special case : don't remove() stdout */ + remove(dstFileName); /* remove decompression artefact; note don't do anything special if remove() fails */ + else { /* operation success */ + if ( strcmp(dstFileName, stdoutmark) /* special case : don't chmod stdout */ + && strcmp(dstFileName, nulmark) /* special case : don't chmod /dev/null */ + && stat_result ) /* file permissions correctly extracted from src */ + UTIL_setFileStat(dstFileName, &statbuf); /* transfer file permissions from src into dst */ + } return result; } From cae3e3c65273ac7871aeeb0bb7318c59860c7749 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 15 Sep 2017 19:00:39 -0700 Subject: [PATCH 150/248] [fse] Fix FSE_optimalTableLog() for srcSize==1 --- lib/compress/fse_compress.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/compress/fse_compress.c b/lib/compress/fse_compress.c index cc9fa7351..599280b90 100644 --- a/lib/compress/fse_compress.c +++ b/lib/compress/fse_compress.c @@ -461,6 +461,7 @@ static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue) U32 minBitsSrc = BIT_highbit32((U32)(srcSize - 1)) + 1; U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2; U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols; + assert(srcSize > 1); /* Not supported, RLE should be used instead */ return minBits; } @@ -469,6 +470,7 @@ unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsi U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus; U32 tableLog = maxTableLog; U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue); + assert(srcSize > 1); /* Not supported, RLE should be used instead */ if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG; if (maxBitsSrc < tableLog) tableLog = maxBitsSrc; /* Accuracy can be reduced */ if (minBits > tableLog) tableLog = minBits; /* Need a minimum to safely represent all symbol values */ From 7d1ff3817b685f691c31f4ce88d7dc70b3260e1a Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 18 Sep 2017 14:47:34 -0700 Subject: [PATCH 151/248] fix ZSTD_sizeof_CCtx() / ZSTD_sizeof_CStream() previous result was over-estimated by counting streaming buffers twice --- lib/compress/zstd_compress.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index f35a44e4c..b0e9195dd 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -134,13 +134,12 @@ static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx) size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) { if (cctx==NULL) return 0; /* support sizeof on NULL */ - DEBUGLOG(5, "sizeof(*cctx) : %u", (U32)sizeof(*cctx)); - DEBUGLOG(5, "workSpaceSize : %u", (U32)cctx->workSpaceSize); - DEBUGLOG(5, "streaming buffers : %u", (U32)(cctx->outBuffSize + cctx->inBuffSize)); - DEBUGLOG(5, "inner MTCTX : %u", (U32)ZSTD_sizeof_mtctx(cctx)); + DEBUGLOG(3, "sizeof(*cctx) : %u", (U32)sizeof(*cctx)); + DEBUGLOG(3, "workSpaceSize (including streaming buffers): %u", (U32)cctx->workSpaceSize); + DEBUGLOG(3, "inner cdict : %u", (U32)ZSTD_sizeof_CDict(cctx->cdictLocal)); + DEBUGLOG(3, "inner MTCTX : %u", (U32)ZSTD_sizeof_mtctx(cctx)); return sizeof(*cctx) + cctx->workSpaceSize + ZSTD_sizeof_CDict(cctx->cdictLocal) - + cctx->outBuffSize + cctx->inBuffSize + ZSTD_sizeof_mtctx(cctx); } From 1fe762e23698ac09cc4df0993350b9f285e5a94e Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Mon, 18 Sep 2017 14:36:17 -0700 Subject: [PATCH 152/248] [zstdcli] Fix LDM advanced options parsing --- programs/zstdcli.c | 4 ++-- tests/playTests.sh | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 78adcb6cd..89e97c294 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -313,8 +313,8 @@ static unsigned parseCompressionParameters(const char* stringPtr, ZSTD_compressi if (longCommandWArg(&stringPtr, "overlapLog=") || longCommandWArg(&stringPtr, "ovlog=")) { g_overlapLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } if (longCommandWArg(&stringPtr, "ldmHashLog=") || longCommandWArg(&stringPtr, "ldmhlog=")) { g_ldmHashLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } if (longCommandWArg(&stringPtr, "ldmSearchLength=") || longCommandWArg(&stringPtr, "ldmslen=")) { g_ldmMinMatch = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } - if (longCommandWArg(&stringPtr, "ldmBucketSizeLog=") || longCommandWArg(&stringPtr, "ldmblog")) { g_ldmBucketSizeLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } - if (longCommandWArg(&stringPtr, "ldmHashEveryLog=") || longCommandWArg(&stringPtr, "ldmhevery")) { g_ldmHashEveryLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } + if (longCommandWArg(&stringPtr, "ldmBucketSizeLog=") || longCommandWArg(&stringPtr, "ldmblog=")) { g_ldmBucketSizeLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } + if (longCommandWArg(&stringPtr, "ldmHashEveryLog=") || longCommandWArg(&stringPtr, "ldmhevery=")) { g_ldmHashEveryLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } return 0; } diff --git a/tests/playTests.sh b/tests/playTests.sh index ed12802c2..38b7a1967 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -161,6 +161,8 @@ roundTripTest -g512K roundTripTest -g512K " --zstd=slen=3,tlen=48,strat=6" roundTripTest -g512K " --zstd=strat=6,wlog=23,clog=23,hlog=22,slog=6" roundTripTest -g512K " --zstd=windowLog=23,chainLog=23,hashLog=22,searchLog=6,searchLength=3,targetLength=48,strategy=6" +roundTripTest -g512K " --long --zstd=ldmHashLog=20,ldmSearchLength=64,ldmBucketSizeLog=1,ldmHashEveryLog=7" +roundTripTest -g512K " --long --zstd=ldmhlog=20,ldmslen=64,ldmblog=1,ldmhevery=7" roundTripTest -g512K 19 From 9c1908a3cde4902c2488d5625fd140e99e2cc850 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 18 Sep 2017 15:49:59 -0700 Subject: [PATCH 153/248] added streaming_memory_usage example --- examples/.gitignore | 1 + examples/Makefile | 28 ++++-- examples/README.md | 4 + examples/streaming_memory_usage.c | 149 ++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 10 deletions(-) create mode 100644 examples/streaming_memory_usage.c diff --git a/examples/.gitignore b/examples/.gitignore index 0711813d3..280feb36e 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -6,6 +6,7 @@ dictionary_decompression streaming_compression streaming_decompression multiple_streaming_compression +streaming_memory_usage #test artefact tmp* diff --git a/examples/Makefile b/examples/Makefile index d1dbc56db..52470f599 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -9,7 +9,7 @@ # This Makefile presumes libzstd is installed, using `sudo make install` -LDFLAGS += -lzstd +LIB = ../lib/libzstd.a .PHONY: default all clean test @@ -18,27 +18,33 @@ default: all all: simple_compression simple_decompression \ dictionary_compression dictionary_decompression \ streaming_compression streaming_decompression \ - multiple_streaming_compression + multiple_streaming_compression streaming_memory_usage -simple_compression : simple_compression.c +$(LIB) : + make -C ../lib libzstd.a + +simple_compression : simple_compression.c $(LIB) $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@ -simple_decompression : simple_decompression.c +simple_decompression : simple_decompression.c $(LIB) $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@ -dictionary_compression : dictionary_compression.c +dictionary_compression : dictionary_compression.c $(LIB) $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@ -dictionary_decompression : dictionary_decompression.c +dictionary_decompression : dictionary_decompression.c $(LIB) $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@ -streaming_compression : streaming_compression.c +streaming_compression : streaming_compression.c $(LIB) $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@ -multiple_streaming_compression : multiple_streaming_compression.c +multiple_streaming_compression : multiple_streaming_compression.c $(LIB) $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@ -streaming_decompression : streaming_decompression.c +streaming_decompression : streaming_decompression.c $(LIB) + $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@ + +streaming_memory_usage : streaming_memory_usage.c $(LIB) $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@ clean: @@ -46,7 +52,7 @@ clean: simple_compression simple_decompression \ dictionary_compression dictionary_decompression \ streaming_compression streaming_decompression \ - multiple_streaming_compression + multiple_streaming_compression streaming_memory_usage @echo Cleaning completed test: all @@ -56,6 +62,8 @@ test: all ./simple_compression tmp ./simple_decompression tmp.zst ./streaming_decompression tmp.zst > /dev/null + @echo -- Streaming memory usage + ./streaming_memory_usage @echo -- Streaming compression tests ./streaming_compression tmp ./streaming_decompression tmp.zst > /dev/null diff --git a/examples/README.md b/examples/README.md index 8a40443ea..eba50c999 100644 --- a/examples/README.md +++ b/examples/README.md @@ -11,6 +11,10 @@ Zstandard library : usage examples Result remains in memory. Introduces usage of : `ZSTD_decompress()` +- [Streaming memory usage](streaming_memory_usage.c) : + Provides amount of memory used by streaming context + Introduces usage of : `ZSTD_sizeof_CStream()` + - [Streaming compression](streaming_compression.c) : Compress a single file. Introduces usage of : `ZSTD_compressStream()` diff --git a/examples/streaming_memory_usage.c b/examples/streaming_memory_usage.c new file mode 100644 index 000000000..b709f50bd --- /dev/null +++ b/examples/streaming_memory_usage.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2017-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. + */ + + +/*=== Tuning parameter ===*/ +#ifndef MAX_TESTED_LEVEL +#define MAX_TESTED_LEVEL 12 +#endif + + +/*=== Dependencies ===*/ +#include /* printf */ +#define ZSTD_STATIC_LINKING_ONLY +#include "zstd.h" + + +/*=== functions ===*/ + +/*! readU32FromChar() : + @return : unsigned integer value read from input in `char` format + allows and interprets K, KB, KiB, M, MB and MiB suffix. + Will also modify `*stringPtr`, advancing it to position where it stopped reading. + Note : function result can overflow if digit string > MAX_UINT */ +static unsigned readU32FromChar(const char** stringPtr) +{ + unsigned result = 0; + while ((**stringPtr >='0') && (**stringPtr <='9')) + result *= 10, result += **stringPtr - '0', (*stringPtr)++ ; + if ((**stringPtr=='K') || (**stringPtr=='M')) { + result <<= 10; + if (**stringPtr=='M') result <<= 10; + (*stringPtr)++ ; + if (**stringPtr=='i') (*stringPtr)++; + if (**stringPtr=='B') (*stringPtr)++; + } + return result; +} + + +int main(int argc, char const *argv[]) { + + printf("\n Zstandard (v%u) memory usage for streaming contexts : \n\n", ZSTD_versionNumber()); + + unsigned wLog = 0; + if (argc > 1) { + const char* valStr = argv[1]; + wLog = readU32FromChar(&valStr); + } + + int compressionLevel; + for (compressionLevel = 1; compressionLevel <= MAX_TESTED_LEVEL; compressionLevel++) { +#define INPUT_SIZE 5 +#define COMPRESSED_SIZE 128 + char const dataToCompress[INPUT_SIZE] = "abcde"; + char compressedData[COMPRESSED_SIZE]; + char decompressedData[INPUT_SIZE]; + ZSTD_CStream* const cstream = ZSTD_createCStream(); + if (cstream==NULL) { + printf("Level %i : ZSTD_CStream Memory allocation failure \n", compressionLevel); + return 1; + } + + /* forces compressor to use maximum memory size for given compression level, + * by not providing any information on input size */ + ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, 0); + if (wLog) { /* special mode : specific wLog */ + printf("Using custom compression parameter : level 1 + wLog=%u \n", wLog); + params = ZSTD_getParams(1, 1 << wLog, 0); + size_t const error = ZSTD_initCStream_advanced(cstream, NULL, 0, params, 0); + if (ZSTD_isError(error)) { + printf("ZSTD_initCStream_advanced error : %s \n", ZSTD_getErrorName(error)); + return 1; + } + } else { + size_t const error = ZSTD_initCStream(cstream, compressionLevel); + if (ZSTD_isError(error)) { + printf("ZSTD_initCStream error : %s \n", ZSTD_getErrorName(error)); + return 1; + } + } + + size_t compressedSize; + { ZSTD_inBuffer inBuff = { dataToCompress, sizeof(dataToCompress), 0 }; + ZSTD_outBuffer outBuff = { compressedData, sizeof(compressedData), 0 }; + size_t const cError = ZSTD_compressStream(cstream, &outBuff, &inBuff); + if (ZSTD_isError(cError)) { + printf("ZSTD_compressStream error : %s \n", ZSTD_getErrorName(cError)); + return 1; + } + size_t const fError = ZSTD_endStream(cstream, &outBuff); + if (ZSTD_isError(fError)) { + printf("ZSTD_endStream error : %s \n", ZSTD_getErrorName(fError)); + return 1; + } + compressedSize = outBuff.pos; + } + + ZSTD_DStream* dstream = ZSTD_createDStream(); + if (dstream==NULL) { + printf("Level %i : ZSTD_DStream Memory allocation failure \n", compressionLevel); + return 1; + } + { size_t const error = ZSTD_initDStream(dstream); + if (ZSTD_isError(error)) { + printf("ZSTD_initDStream error : %s \n", ZSTD_getErrorName(error)); + return 1; + } + } + /* forces decompressor to use maximum memory size, as decompressed size is not known */ + { ZSTD_inBuffer inBuff = { compressedData, compressedSize, 0 }; + ZSTD_outBuffer outBuff = { decompressedData, sizeof(decompressedData), 0 }; + size_t const dResult = ZSTD_decompressStream(dstream, &outBuff, &inBuff); + if (ZSTD_isError(dResult)) { + printf("ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(dResult)); + return 1; + } + if (dResult != 0) { + printf("ZSTD_decompressStream error : unfinished decompression \n"); + return 1; + } + if (outBuff.pos != sizeof(dataToCompress)) { + printf("ZSTD_decompressStream error : incorrect decompression \n"); + return 1; + } + } + + size_t const cstreamSize = ZSTD_sizeof_CStream(cstream); + size_t const cstreamEstimatedSize = wLog ? + ZSTD_estimateCStreamSize_advanced_usingCParams(params.cParams) : + ZSTD_estimateCStreamSize(compressionLevel); + size_t const dstreamSize = ZSTD_sizeof_DStream(dstream); + + printf("Level %2i : Compression Mem = %5u KB (estimated : %5u KB) ; Decompression Mem = %4u KB \n", + compressionLevel, + (unsigned)(cstreamSize>>10), (unsigned)(cstreamEstimatedSize>>10), (unsigned)(dstreamSize>>10)); + + ZSTD_freeDStream(dstream); + ZSTD_freeCStream(cstream); + if (wLog) break; /* single test */ + } + return 0; +} From 18442a31ff4b87263a6138369e8d0880346af0bd Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 19 Sep 2017 13:46:07 -0700 Subject: [PATCH 154/248] [libzstd] Fix bad window size assert The window size is not validated or used in the one-pass API, so there shouldn't be an assert based on it. fix-fuzz-failure --- lib/decompress/zstd_decompress.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 6d6d83396..91518990e 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -1372,8 +1372,9 @@ static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, * conservative. */ ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN))); - /* We don't expect window sizes this big. */ - assert(!frame || dctx->fParams.windowSize <= (1ULL << STREAM_ACCUMULATOR_MIN_64)); + /* windowSize could be any value at this point, since it is only validated + * in the streaming API. + */ DEBUGLOG(5, "ZSTD_decompressBlock_internal"); if (srcSize >= ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); From 6c9ed76676075f3772948aae98fdaab69e376370 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 19 Sep 2017 13:49:37 -0700 Subject: [PATCH 155/248] [ldm] Fix corner case where minMatch < 8 There is a potential read buffer overflow when minMatch < 8. fix-fuzz-failure --- lib/compress/zstd_ldm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/compress/zstd_ldm.c b/lib/compress/zstd_ldm.c index e7efecdb9..e40007c19 100644 --- a/lib/compress/zstd_ldm.c +++ b/lib/compress/zstd_ldm.c @@ -295,7 +295,7 @@ size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx, const U32 lowestIndex = cctx->dictLimit; const BYTE* const lowest = base + lowestIndex; const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = iend - ldmParams.minMatchLength; + const BYTE* const ilimit = iend - MAX(ldmParams.minMatchLength, HASH_READ_SIZE); const ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(cctx->appliedParams.cParams.strategy, 0); @@ -499,7 +499,7 @@ static size_t ZSTD_compressBlock_ldm_extDict_generic( const BYTE* const lowPrefixPtr = base + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = iend - ldmParams.minMatchLength; + const BYTE* const ilimit = iend - MAX(ldmParams.minMatchLength, HASH_READ_SIZE); const ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(ctx->appliedParams.cParams.strategy, 1); From 74718d7e4386c44bfa564f669348748a99643b39 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 15 Sep 2017 17:44:09 -0700 Subject: [PATCH 156/248] [bitstream] Allow adding 31 bits at a time --- lib/common/bitstream.h | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/common/bitstream.h b/lib/common/bitstream.h index c6f001248..2094823fe 100644 --- a/lib/common/bitstream.h +++ b/lib/common/bitstream.h @@ -194,11 +194,14 @@ MEM_STATIC unsigned BIT_highbit32 (register U32 val) } /*===== Local Constants =====*/ -static const unsigned BIT_mask[] = { 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, - 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, - 0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, - 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF }; /* up to 26 bits */ - +static const unsigned BIT_mask[] = { + 0, 1, 3, 7, 0xF, 0x1F, + 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, + 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, + 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, + 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF, + 0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */ +#define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0])) /*-************************************************************** * bitStream encoding @@ -220,11 +223,14 @@ MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, } /*! BIT_addBits() : - * can add up to 26 bits into `bitC`. + * can add up to 31 bits into `bitC`. * Note : does not check for register overflow ! */ MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits) { + MEM_STATIC_ASSERT(BIT_MASK_SIZE == 32); + assert(nbBits < BIT_MASK_SIZE); + assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos; bitC->bitPos += nbBits; } @@ -235,6 +241,7 @@ MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits) { assert((value>>nbBits) == 0); + assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); bitC->bitContainer |= value << bitC->bitPos; bitC->bitPos += nbBits; } @@ -245,7 +252,7 @@ MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC) { size_t const nbBytes = bitC->bitPos >> 3; - assert( bitC->bitPos <= (sizeof(bitC->bitContainer)*8) ); + assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8); MEM_writeLEST(bitC->ptr, bitC->bitContainer); bitC->ptr += nbBytes; assert(bitC->ptr <= bitC->endPtr); @@ -261,7 +268,7 @@ MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC) MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC) { size_t const nbBytes = bitC->bitPos >> 3; - assert( bitC->bitPos <= (sizeof(bitC->bitContainer)*8) ); + assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8); MEM_writeLEST(bitC->ptr, bitC->bitContainer); bitC->ptr += nbBytes; if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr; @@ -353,12 +360,14 @@ MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 co # endif return _bextr_u32(bitContainer, start, nbBits); #else + assert(nbBits < BIT_MASK_SIZE); return (bitContainer >> start) & BIT_mask[nbBits]; #endif } MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) { + assert(nbBits < BIT_MASK_SIZE); return bitContainer & BIT_mask[nbBits]; } From f97c2dbd395e64bb4d58948622f15961181307c0 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 21 Sep 2017 16:07:29 -0700 Subject: [PATCH 157/248] created ZSTD_format declaration --- NEWS | 3 ++- lib/zstd.h | 19 ++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index bb7eaaca8..cddc8fc13 100644 --- a/NEWS +++ b/NEWS @@ -3,7 +3,8 @@ new : long range mode, using --long command, by Stella Lau (@stellamplau) license : changed /examples license to BSD + GPLv2 license : fix a few header files to reflect new license (#825) fix : multi-threading compression works with custom allocators -fix : a rare compression bug when compression generates very large distances (only possible at --ultra -22) +fix : ZSTD_sizeof_CStream() was over-evaluating memory usage +fix : a rare compression bug when compression generates very large distances and bunch of other conditions (only possible at --ultra -22) fix : 32-bits build can now decode large offsets (levels 21+) cli : new : can split input file for dictionary training, using command -B# cli : fix : do not change /dev/null permissions when using command -t with root access, reported by @mike155 (#851) diff --git a/lib/zstd.h b/lib/zstd.h index ddb284299..ca699dae2 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -927,14 +927,27 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); * The main driver is that it identifies more clearly the target object type. * It feels clearer in light of potential variants : * ZSTD_CDict_setParameter() (rather than ZSTD_setCDictParameter()) - * ZSTD_DCtx_setParameter() (rather than ZSTD_setDCtxParameter() ) - * Left variant feels easier to distinguish. + * ZSTD_CCtxParams_setParameter() (rather than ZSTD_setCCtxParamsParameter() ) */ /* note on enum design : * All enum will be manually set to explicit values before reaching "stable API" status */ typedef enum { + ZSTD_f_zstd1, /* Normal (default) zstd frame format, as specified in zstd_compression_format.md */ + ZSTD_f_zstd1_magicLess, /* Almost zstd frame format, but without initial 4-bytes magic number */ + ZSTD_f_zstd1_headerless, /* Almost zstd frame format, but without any frame header; + * Other metadata, like block size or frame checksum, are still generated */ + ZSTD_f_zstd_block /* Pure zstd compressed block, without any metadata. + * Note that size of uncompressed block must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB. + * See ZSTD_compressBlock() for more details. */ +} ZSTD_format; + +typedef enum { + /* compression format */ + ZSTD_p_format = 10, /* See ZSTD_format enum definition. + * Cast selected strategy as unsigned for ZSTD_CCtx_setParameter() compatibility. */ + /* compression parameters */ ZSTD_p_compressionLevel=100, /* Update all compression parameters according to pre-defined cLevel table * Default level is ZSTD_CLEVEL_DEFAULT==3. @@ -1216,7 +1229,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( + compression : any ZSTD_compressBegin*() variant, including with dictionary + decompression : any ZSTD_decompressBegin*() variant, including with dictionary + copyCCtx() and copyDCtx() can be used too - - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX + - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB + If input is larger than a block size, it's necessary to split input data into multiple blocks + For inputs larger than a single block size, consider using the regular ZSTD_compress() instead. Frame metadata is not that costly, and quickly becomes negligible as source size grows larger. From cd3115b284f47abea84bcf82f3c45d42062393a1 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 21 Sep 2017 16:21:10 -0700 Subject: [PATCH 158/248] added control from frame content size at end of decompression adding check at end of single-pass ZSTD_decompressFrame(). Check within ZSTD_decompressContinue() was already added in a previous patch : b3f33ccfb3b4fcc73df82126fd5ecfb751268fc6 --- lib/decompress/zstd_decompress.c | 4 ++++ tests/fuzzer.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 91518990e..2abcc145e 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -1546,6 +1546,10 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, if (blockProperties.lastBlock) break; } + if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) { + if ((U64)(op-ostart) != dctx->fParams.frameContentSize) { + return ERROR(corruption_detected); + } } if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */ U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); U32 checkRead; diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 2bc5c9dfe..bfa290c62 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -811,7 +811,7 @@ static int basicUnitTests(U32 seed, double compressibility) } DISPLAYLEVEL(4, "OK \n"); - DISPLAYLEVEL(4, "test%3i : Loading rawContent starting with dict header w/ ZSTD_dm_auto should fail", testNb++); + DISPLAYLEVEL(4, "test%3i : Loading rawContent starting with dict header w/ ZSTD_dm_auto should fail : ", testNb++); { size_t ret; MEM_writeLE32((char*)dictBuffer+2, ZSTD_MAGIC_DICTIONARY); @@ -821,7 +821,7 @@ static int basicUnitTests(U32 seed, double compressibility) } DISPLAYLEVEL(4, "OK \n"); - DISPLAYLEVEL(4, "test%3i : Loading rawContent starting with dict header w/ ZSTD_dm_rawContent should pass", testNb++); + DISPLAYLEVEL(4, "test%3i : Loading rawContent starting with dict header w/ ZSTD_dm_rawContent should pass : ", testNb++); { size_t ret; MEM_writeLE32((char*)dictBuffer+2, ZSTD_MAGIC_DICTIONARY); From d6abb28951e01cb4042d1e075c822106c31b7d49 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 21 Sep 2017 16:18:34 -0700 Subject: [PATCH 159/248] Prepare for ZSTD_WINDOWLOG_MAX == 31 --- lib/compress/zstd_compress.c | 33 ++++++++++++++++++++++++++------ lib/decompress/zstd_decompress.c | 2 +- lib/zstd.h | 4 ++-- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index b0e9195dd..c58d30442 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -675,7 +675,7 @@ size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* pa size_t const maxNbSeq = blockSize / divider; size_t const tokenSpace = blockSize + 11*maxNbSeq; size_t const chainSize = - (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog); + (cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams.chainLog); size_t const hSize = ((size_t)1) << cParams.hashLog; U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog); @@ -833,7 +833,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, size_t const maxNbSeq = blockSize / divider; size_t const tokenSpace = blockSize + 11*maxNbSeq; size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? - 0 : (1 << params.cParams.chainLog); + 0 : ((size_t)1 << params.cParams.chainLog); size_t const hSize = ((size_t)1) << params.cParams.hashLog; U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog); @@ -1005,7 +1005,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, } /* copy tables */ - { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->appliedParams.cParams.chainLog); + { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog); size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog; size_t const h3Size = (size_t)1 << srcCCtx->hashLog3; size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); @@ -1599,13 +1599,33 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */ if (remaining < blockSize) blockSize = remaining; - /* preemptive overflow correction */ + /* preemptive overflow correction: + * 1. correction is large enough: + * lowLimit > (3<<29) ==> current > 3<<29 + 1< (3<<29 + 1< (3<<29 - blockSize) - (1< (3<<29 - blockSize) - (1<<30) (NOTE: chainLog <= 30) + * > 1<<29 - 1<<17 + * + * 2. (ip+blockSize - cctx->base) doesn't overflow: + * In 32 bit mode we limit windowLog to 30 so we don't get + * differences larger than 1<<31-1. + * 3. cctx->lowLimit < 1<<32: + * windowLog <= 31 ==> 3<<29 + 1<lowLimit > (3U<<29)) { - U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->appliedParams.cParams.hashLog, cctx->appliedParams.cParams.strategy)) - 1; + U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy)) - 1; U32 const current = (U32)(ip - cctx->base); U32 const newCurrent = (current & cycleMask) + (1 << cctx->appliedParams.cParams.windowLog); U32 const correction = current - newCurrent; - ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30); + ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); + ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); + ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); + assert(current > newCurrent); + assert(correction > 1<<28); /* Loose bound, should be about 1<<29 */ ZSTD_reduceIndex(cctx, correction); cctx->base += correction; cctx->dictBase += correction; @@ -1613,6 +1633,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, cctx->dictLimit -= correction; if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0; else cctx->nextToUpdate -= correction; + DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x\n", correction, cctx->lowLimit); } if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) { diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 91518990e..b07d77cf5 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -35,7 +35,7 @@ * Frames requiring more memory will be rejected. */ #ifndef ZSTD_MAXWINDOWSIZE_DEFAULT -# define ZSTD_MAXWINDOWSIZE_DEFAULT ((1 << ZSTD_WINDOWLOG_MAX) + 1) /* defined within zstd.h */ +# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U64)1 << ZSTD_WINDOWLOG_MAX) + 1) /* defined within zstd.h */ #endif diff --git a/lib/zstd.h b/lib/zstd.h index ddb284299..a6266dfd8 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -380,9 +380,9 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output #define ZSTD_WINDOWLOG_MAX_64 27 #define ZSTD_WINDOWLOG_MAX ((unsigned)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64)) #define ZSTD_WINDOWLOG_MIN 10 -#define ZSTD_HASHLOG_MAX ZSTD_WINDOWLOG_MAX +#define ZSTD_HASHLOG_MAX MIN(ZSTD_WINDOWLOG_MAX, 30) #define ZSTD_HASHLOG_MIN 6 -#define ZSTD_CHAINLOG_MAX (ZSTD_WINDOWLOG_MAX+1) +#define ZSTD_CHAINLOG_MAX MIN(ZSTD_WINDOWLOG_MAX+1, 30) #define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN #define ZSTD_HASHLOG3_MAX 17 #define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1) From 360238733a50e3c5397b0665f6653d976f7d0e43 Mon Sep 17 00:00:00 2001 From: "W. Felix Handte" Date: Thu, 21 Sep 2017 11:29:35 -0700 Subject: [PATCH 160/248] Adds LZ4 support by default if LZ4 is available Simple makefile change + quick typename change Test: make clean make # successfully produces binary without lz4 support make clean # with flags to pick up my lz4 build make MOREFLAGS="-L/home/felixh/prog/lz4/lib -I/home/felixh/prog/lz4/lib" # successfully produces binary with lz4 support echo "TEST TEST TEST THIS IS A TEST STRING PLEASE TEST THIS PLEASE OK THANK YOU" | \ ./lz4/lz4 | \ LD_LIBRARY_PATH=/home/felixh/prog/lz4/lib ./zstd/zstd -d # successfully prints TEST TEST TEST THIS IS A TEST STRING PLEASE TEST THIS PLEASE OK THANK YOU --- programs/Makefile | 11 ++++------- programs/fileio.c | 1 + 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/programs/Makefile b/programs/Makefile index b13629df9..7aa4331ec 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -140,13 +140,10 @@ allVariants: zstd zstd-compress zstd-decompress zstd-small zstd-nolegacy $(ZSTDDECOMP_O): CFLAGS += $(ALIGN_LOOP) -zstd zstd4 : CPPFLAGS += $(THREAD_CPP) $(ZLIBCPP) $(LZMACPP) -zstd zstd4 : LDFLAGS += $(THREAD_LD) $(ZLIBLD) $(LZMALD) -zstd4 : CPPFLAGS += $(LZ4CPP) -zstd4 : LDFLAGS += $(LZ4LD) -zstd : LZ4_MSG := - lz4 support is disabled -zstd zstd4 : CPPFLAGS += -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) -zstd zstd4 : $(ZSTDLIB_FILES) zstdcli.o fileio.o bench.o datagen.o dibio.o +zstd : CPPFLAGS += $(THREAD_CPP) $(ZLIBCPP) $(LZMACPP) $(LZ4CPP) +zstd : LDFLAGS += $(THREAD_LD) $(ZLIBLD) $(LZMALD) $(LZ4LD) +zstd : CPPFLAGS += -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) +zstd : $(ZSTDLIB_FILES) zstdcli.o fileio.o bench.o datagen.o dibio.o @echo "$(THREAD_MSG)" @echo "$(ZLIB_MSG)" @echo "$(LZMA_MSG)" diff --git a/programs/fileio.c b/programs/fileio.c index 623c4f4df..b43994888 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -56,6 +56,7 @@ #define LZ4_MAGICNUMBER 0x184D2204 #if defined(ZSTD_LZ4COMPRESS) || defined(ZSTD_LZ4DECOMPRESS) +# define LZ4F_ENABLE_OBSOLETE_ENUMS # include # include #endif From 7c3dea42cebf9a1c67136078988825a6ab22bee9 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 24 Sep 2017 15:57:29 -0700 Subject: [PATCH 161/248] added prototypes for advanced parameters for decompression API required to decode custom formats --- doc/zstd_manual.html | 150 +++++++++++++++++++++++++------- lib/common/zstd_internal.h | 1 + lib/compress/zstd_compress.c | 9 ++ lib/zstd.h | 160 ++++++++++++++++++++++++++--------- 4 files changed, 251 insertions(+), 69 deletions(-) diff --git a/doc/zstd_manual.html b/doc/zstd_manual.html index e7d861707..64870229b 100644 --- a/doc/zstd_manual.html +++ b/doc/zstd_manual.html @@ -27,8 +27,8 @@
  • Buffer-less and synchronous inner streaming functions
  • Buffer-less streaming compression (synchronous mode)
  • Buffer-less streaming decompression (synchronous mode)
  • -
  • ZSTD_CCtx_params
  • -
  • Block functions
  • +
  • === New advanced API (experimental) ===
  • +
  • === Block level API ===

  • Introduction

    @@ -399,7 +399,7 @@ size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds);
     size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict);
     size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
     

    These functions give the current memory usage of selected object. - Object memory usage can evolve if it's re-used multiple times. + Object memory usage can evolve when re-used multiple times.


    size_t ZSTD_estimateCCtxSize(int compressionLevel);
    @@ -646,12 +646,12 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict*
       @return : 0, or an error code (which can be tested using ZSTD_isError()) 
     


    -

    Advanced Streaming decompression functions

    typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
    -ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
    +

    Advanced Streaming decompression functions

    ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
     ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize);    /**< same as ZSTD_initStaticDCtx() */
    +typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
     size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue);
    -size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: a dict will not be used if dict == NULL or dictSize < 8 */
    -size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict);  /**< note : ddict will just be referenced, and must outlive decompression session */
    +size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: no dictionary will be used if dict == NULL or dictSize < 8 */
    +size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict);  /**< note : ddict is referenced, it must outlive decompression session */
     size_t ZSTD_resetDStream(ZSTD_DStream* zds);  /**< re-use decompression parameters from previous init; saves dictionary loading */
     

    Buffer-less and synchronous inner streaming functions

    @@ -783,8 +783,29 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
     

    typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
     

    -

    New advanced API (experimental, and compression only)


    +

    === New advanced API (experimental) ===

    
    +
     
    typedef enum {
    +    ZSTD_f_zstd1 = 0,        /* Normal zstd frame format, specified in zstd_compression_format.md (default) */
    +    ZSTD_f_zstd1_magicless,  /* Variant of zstd frame format, without initial 4-bytes magic number.
    +                              * Useful to save 4 bytes per generated frame.
    +                              * Decoder will not be able to recognise this format, requiring instructions. */
    +    ZSTD_f_zstd1_headerless, /* Variant of zstd frame format, without any frame header;
    +                              * Other metadata, like block size or frame checksum, are still generated.
    +                              * Useful to save between 6 and ZSTD_frameHeaderSize_max bytes per generated frame.
    +                              * However, required decoding parameters will have to be saved or known by some mechanism.
    +                              * Decoder will not be able to recognise this format, requiring instructions and parameters. */
    +    ZSTD_f_zstd1_block       /* Generate a zstd compressed block, without any metadata.
    +                              * Note that size of block content must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB.
    +                              * See ZSTD_compressBlock() for more details.
    +                              * Resulting compressed block can be decoded with ZSTD_decompressBlock(). */
    +} ZSTD_format_e;
    +

    +
    typedef enum {
    +    /* compression format */
    +    ZSTD_p_format = 10,      /* See ZSTD_format_e enum definition.
    +                              * Cast selected format as unsigned for ZSTD_CCtx_setParameter() compatibility. */
    +
         /* compression parameters */
         ZSTD_p_compressionLevel=100, /* Update all compression parameters according to pre-defined cLevel table
                                   * Default level is ZSTD_CLEVEL_DEFAULT==3.
    @@ -949,7 +970,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
     
    typedef enum {
         ZSTD_e_continue=0, /* collect more data, encoder transparently decides when to output result, for optimal conditions */
         ZSTD_e_flush,      /* flush any data provided so far - frame will continue, future data can still reference previous data for better compression */
    -    ZSTD_e_end         /* flush any remaining data and ends current frame. Any future compression starts a new frame. */
    +    ZSTD_e_end         /* flush any remaining data and close current frame. Any additional data starts a new frame. */
     } ZSTD_EndDirective;
     

    size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
    @@ -959,8 +980,8 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
     

    Behave about the same as ZSTD_compressStream. To note : - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_setParameter() - Compression parameters cannot be changed once compression is started. - - *dstPos must be <= dstCapacity, *srcPos must be <= srcSize - - *dspPos and *srcPos will be updated. They are guaranteed to remain below their respective limit. + - outpot->pos must be <= dstCapacity, input->pos must be <= srcSize + - outpot->pos and input->pos will be updated. They are guaranteed to remain below their respective limit. - @return provides the minimum amount of data still to flush from internal buffers or an error code, which can be tested using ZSTD_isError(). if @return != 0, flush is not fully completed, there is some data left within internal buffers. @@ -976,6 +997,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t Useful after an error, or to interrupt an ongoing compression job and start a new one. Any internal data not yet flushed is cancelled. Dictionary (if any) is dropped. + All parameters are back to default values. It's possible to modify compression parameters after a reset.


    @@ -987,26 +1009,30 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t ZSTD_EndDirective endOp);

    Same as ZSTD_compress_generic(), but using only integral types as arguments. - Argument list is larger and less expressive than ZSTD_{in,out}Buffer, + Argument list is larger than ZSTD_{in,out}Buffer, but can be helpful for binders from dynamic languages which have troubles handling structures containing memory pointers.


    -

    ZSTD_CCtx_params

    +
    ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
    +

    Quick howto : - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure - - ZSTD_CCtxParam_setParameter() : Push parameters one by one into an - existing ZSTD_CCtx_params structure. This is similar to - ZSTD_CCtx_setParameter(). - - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to an existing CCtx. These - parameters will be applied to all subsequent compression jobs. + - ZSTD_CCtxParam_setParameter() : Push parameters one by one into + an existing ZSTD_CCtx_params structure. + This is similar to + ZSTD_CCtx_setParameter(). + - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to + an existing CCtx. + These parameters will be applied to + all subsequent compression jobs. - ZSTD_compress_generic() : Do compression using the CCtx. - ZSTD_freeCCtxParams() : Free the memory. - This can be used with ZSTD_estimateCCtxSize_opaque() for static allocation - for single-threaded compression. + This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams() + for static allocation for single-threaded compression. -

    +


    size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params);
     

    Reset params to default, with the default compression level. @@ -1030,22 +1056,84 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t Set one compression parameter, selected by enum ZSTD_cParameter. Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams(). Note : when `value` is an enum, cast it to unsigned for proper type checking. - @result : 0, or an error code (which can be tested with ZSTD_isError()). + @result : 0, or an error code (which can be tested with ZSTD_isError()).


    size_t ZSTD_CCtx_setParametersUsingCCtxParams(
             ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
    -

    Apply a set of ZSTD_CCtx_params to the compression context. - This must be done before the dictionary is loaded. - The pledgedSrcSize is treated as unknown. - Multithreading parameters are applied only if nbThreads > 1. +

    Apply a set of ZSTD_CCtx_params to the compression context. + This must be done before the dictionary is loaded. + The pledgedSrcSize is treated as unknown. + Multithreading parameters are applied only if nbThreads > 1.


    -

    Block functions

    -    Block functions produce and decode raw zstd blocks, without frame metadata.
    -    Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
    +

    Advanced parameters for decompression API


    +
    size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
    +size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
    +size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode);
    +

    Create an internal DDict from dict buffer, + to be used to decompress next frames. + @result : 0, or an error code (which can be tested with ZSTD_isError()). + Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary, + meaning "return to no-dictionary mode". + Note 1 : `dict` content will be copied internally. + Use ZSTD_DCtx_loadDictionary_byReference() + to reference dictionary content instead. + In which case, the dictionary buffer must outlive its users. + Note 2 : Loading a dictionary involves building tables, + which has a non-negligible impact on CPU usage and latency. + Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to select + how dictionary content will be interpreted and loaded. + +


    + +
    size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
    +

    Reference a prepared dictionary, to be used to decompress next frames. + The dictionary remains active for decompression of future frames using same DCtx. + @result : 0, or an error code (which can be tested with ZSTD_isError()). + Note 1 : Currently, only one dictionary can be managed. + Referencing a new dictionary effectively "discards" any previous one. + Special : adding a NULL DDict means "return to no-dictionary mode". + Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx. + +


    + +
    size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize);
    +size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode);
    +

    Reference a prefix (single-usage dictionary) for next compression job. + Prefix is **only used once**. It must be explicitly referenced before each frame. + If there is a need to use same prefix multiple times, consider embedding it into a ZSTD_DDict instead. + @result : 0, or an error code (which can be tested with ZSTD_isError()). + Note 1 : Adding any prefix (including NULL) invalidates any previously set prefix or dictionary + Note 2 : Prefix buffer is referenced. It must outlive compression job. + Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent). + Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode. + Note 4 : Referencing a raw content prefix costs almost nothing cpu and memory wise. + +


    + +
    size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize);
    +

    Refuses allocating internal buffers for frames requiring a window size larger than provided limit. + This is useful to prevent a decoder context from reserving too much memory for itself (potential attack scenario). + This parameter is only useful in streaming mode, since no internal buffer is allocated in direct mode. + By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_MAX) + @return : 0, or an error code (which can be tested using ZSTD_isError()). + +


    + +
    size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
    +

    Instruct the decoder context about what kind of data to decode next. + This instruction is mandatory to decode data without a fully-formed header, + such ZSTD_f_zstd1_magicless for example. + @return : 0, or an error code (which can be tested using ZSTD_isError()). + +


    + +

    === Block level API ===

    
    +
    +

    Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes). User will have to take in charge required information to regenerate data, such as compressed and content sizes. A few rules to respect : @@ -1055,7 +1143,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t + compression : any ZSTD_compressBegin*() variant, including with dictionary + decompression : any ZSTD_decompressBegin*() variant, including with dictionary + copyCCtx() and copyDCtx() can be used too - - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX + - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB + If input is larger than a block size, it's necessary to split input data into multiple blocks + For inputs larger than a single block size, consider using the regular ZSTD_compress() instead. Frame metadata is not that costly, and quickly becomes negligible as source size grows larger. @@ -1066,7 +1154,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t + In case of multiple successive blocks, should some of them be uncompressed, decoder must be informed of their existence in order to follow proper history. Use ZSTD_insertBlock() for such a case. -

    +


    Raw zstd block functions

    size_t ZSTD_getBlockSize   (const ZSTD_CCtx* cctx);
     size_t ZSTD_compressBlock  (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
    diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h
    index cd0dbcc27..8a24d42f2 100644
    --- a/lib/common/zstd_internal.h
    +++ b/lib/common/zstd_internal.h
    @@ -282,6 +282,7 @@ typedef struct {
     } ZSTD_entropyCTables_t;
     
     struct ZSTD_CCtx_params_s {
    +    ZSTD_format_e format;
         ZSTD_compressionParameters cParams;
         ZSTD_frameParameters fParams;
     
    diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
    index c58d30442..88eb51dcb 100644
    --- a/lib/compress/zstd_compress.c
    +++ b/lib/compress/zstd_compress.c
    @@ -256,6 +256,9 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
     
         switch(param)
         {
    +    case ZSTD_p_format :
    +        return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
    +
         case ZSTD_p_compressionLevel:
             if (value == 0) return 0;  /* special value : 0 means "don't change anything" */
             if (cctx->cdict) return ERROR(stage_wrong);
    @@ -326,6 +329,12 @@ size_t ZSTD_CCtxParam_setParameter(
     {
         switch(param)
         {
    +    case ZSTD_p_format :
    +        if (value > (unsigned)ZSTD_f_zstd1_block)
    +            return ERROR(parameter_unsupported);
    +        params->format = (ZSTD_format_e)value;
    +        return 0;
    +
         case ZSTD_p_compressionLevel :
             if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel();
             if (value == 0) return 0;
    diff --git a/lib/zstd.h b/lib/zstd.h
    index 81158a20b..655fa29d3 100644
    --- a/lib/zstd.h
    +++ b/lib/zstd.h
    @@ -486,7 +486,7 @@ ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize);
     
     /*! ZSTD_sizeof_*() :
      *  These functions give the current memory usage of selected object.
    - *  Object memory usage can evolve if it's re-used multiple times. */
    + *  Object memory usage can evolve when re-used multiple times. */
     ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);
     ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx);
     ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs);
    @@ -747,12 +747,12 @@ ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledg
     
     
     /*=====   Advanced Streaming decompression functions  =====*/
    -typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
     ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
     ZSTDLIB_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize);    /**< same as ZSTD_initStaticDCtx() */
    +typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
     ZSTDLIB_API size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue);
    -ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: a dict will not be used if dict == NULL or dictSize < 8 */
    -ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict);  /**< note : ddict will just be referenced, and must outlive decompression session */
    +ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: no dictionary will be used if dict == NULL or dictSize < 8 */
    +ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict);  /**< note : ddict is referenced, it must outlive decompression session */
     ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);  /**< re-use decompression parameters from previous init; saves dictionary loading */
     
     
    @@ -908,17 +908,17 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
     
     
     
    -/*===   New advanced API (experimental, and compression only)  ===*/
    +/** ===   New advanced API (experimental)  === **/
     
     /* notes on API design :
    - *   In this proposal, parameters are pushed one by one into an existing CCtx,
    + *   In this proposal, parameters are pushed one by one into an existing context,
      *   and then applied on all subsequent compression jobs.
      *   When no parameter is ever provided, CCtx is created with compression level ZSTD_CLEVEL_DEFAULT.
      *
      *   This API is intended to replace all others experimental API.
      *   It can basically do all other use cases, and even new ones.
    - *   It stands a good chance to become "stable",
    - *   after a reasonable testing period.
    + *   In constrast with _advanced() variants, it stands a reasonable chance to become "stable",
    + *   after a testing period.
      */
     
     /* note on naming convention :
    @@ -934,19 +934,25 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
      * All enum will be manually set to explicit values before reaching "stable API" status */
     
     typedef enum {
    -    ZSTD_f_zstd1,            /* Normal (default) zstd frame format, as specified in zstd_compression_format.md */
    -    ZSTD_f_zstd1_magicLess,  /* Almost zstd frame format, but without initial 4-bytes magic number */
    -    ZSTD_f_zstd1_headerless, /* Almost zstd frame format, but without any frame header;
    -                              * Other metadata, like block size or frame checksum, are still generated */
    -    ZSTD_f_zstd_block        /* Pure zstd compressed block, without any metadata.
    -                              * Note that size of uncompressed block must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB.
    -                              * See ZSTD_compressBlock() for more details. */
    -} ZSTD_format;
    +    ZSTD_f_zstd1 = 0,        /* Normal zstd frame format, specified in zstd_compression_format.md (default) */
    +    ZSTD_f_zstd1_magicless,  /* Variant of zstd frame format, without initial 4-bytes magic number.
    +                              * Useful to save 4 bytes per generated frame.
    +                              * Decoder will not be able to recognise this format, requiring instructions. */
    +    ZSTD_f_zstd1_headerless, /* Variant of zstd frame format, without any frame header;
    +                              * Other metadata, like block size or frame checksum, are still generated.
    +                              * Useful to save between 6 and ZSTD_frameHeaderSize_max bytes per generated frame.
    +                              * However, required decoding parameters will have to be saved or known by some mechanism.
    +                              * Decoder will not be able to recognise this format, requiring instructions and parameters. */
    +    ZSTD_f_zstd1_block       /* Generate a zstd compressed block, without any metadata.
    +                              * Note that size of block content must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB.
    +                              * See ZSTD_compressBlock() for more details.
    +                              * Resulting compressed block can be decoded with ZSTD_decompressBlock(). */
    +} ZSTD_format_e;
     
     typedef enum {
         /* compression format */
    -    ZSTD_p_format = 10,      /* See ZSTD_format enum definition.
    -                              * Cast selected strategy as unsigned for ZSTD_CCtx_setParameter() compatibility. */
    +    ZSTD_p_format = 10,      /* See ZSTD_format_e enum definition.
    +                              * Cast selected format as unsigned for ZSTD_CCtx_setParameter() compatibility. */
     
         /* compression parameters */
         ZSTD_p_compressionLevel=100, /* Update all compression parameters according to pre-defined cLevel table
    @@ -1116,15 +1122,15 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* pre
     typedef enum {
         ZSTD_e_continue=0, /* collect more data, encoder transparently decides when to output result, for optimal conditions */
         ZSTD_e_flush,      /* flush any data provided so far - frame will continue, future data can still reference previous data for better compression */
    -    ZSTD_e_end         /* flush any remaining data and ends current frame. Any future compression starts a new frame. */
    +    ZSTD_e_end         /* flush any remaining data and close current frame. Any additional data starts a new frame. */
     } ZSTD_EndDirective;
     
     /*! ZSTD_compress_generic() :
      *  Behave about the same as ZSTD_compressStream. To note :
      *  - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_setParameter()
      *  - Compression parameters cannot be changed once compression is started.
    - *  - *dstPos must be <= dstCapacity, *srcPos must be <= srcSize
    - *  - *dspPos and *srcPos will be updated. They are guaranteed to remain below their respective limit.
    + *  - outpot->pos must be <= dstCapacity, input->pos must be <= srcSize
    + *  - outpot->pos and input->pos will be updated. They are guaranteed to remain below their respective limit.
      *  - @return provides the minimum amount of data still to flush from internal buffers
      *            or an error code, which can be tested using ZSTD_isError().
      *            if @return != 0, flush is not fully completed, there is some data left within internal buffers.
    @@ -1143,6 +1149,7 @@ ZSTDLIB_API size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
      *  Useful after an error, or to interrupt an ongoing compression job and start a new one.
      *  Any internal data not yet flushed is cancelled.
      *  Dictionary (if any) is dropped.
    + *  All parameters are back to default values.
      *  It's possible to modify compression parameters after a reset.
      */
     ZSTDLIB_API void ZSTD_CCtx_reset(ZSTD_CCtx* cctx);   /* Not ready yet ! */
    @@ -1151,7 +1158,7 @@ ZSTDLIB_API void ZSTD_CCtx_reset(ZSTD_CCtx* cctx);   /* Not ready yet ! */
     /*! ZSTD_compress_generic_simpleArgs() :
      *  Same as ZSTD_compress_generic(),
      *  but using only integral types as arguments.
    - *  Argument list is larger and less expressive than ZSTD_{in,out}Buffer,
    + *  Argument list is larger than ZSTD_{in,out}Buffer,
      *  but can be helpful for binders from dynamic languages
      *  which have troubles handling structures containing memory pointers.
      */
    @@ -1162,19 +1169,22 @@ size_t ZSTD_compress_generic_simpleArgs (
                                 ZSTD_EndDirective endOp);
     
     
    -/** ZSTD_CCtx_params
    - *
    +/*! ZSTD_CCtx_params :
    + *  Quick howto :
      *  - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure
    - *  - ZSTD_CCtxParam_setParameter() : Push parameters one by one into an
    - *  existing ZSTD_CCtx_params structure. This is similar to
    - *  ZSTD_CCtx_setParameter().
    - *  - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to an existing CCtx. These
    - *  parameters will be applied to all subsequent compression jobs.
    + *  - ZSTD_CCtxParam_setParameter() : Push parameters one by one into
    + *                                    an existing ZSTD_CCtx_params structure.
    + *                                    This is similar to
    + *                                    ZSTD_CCtx_setParameter().
    + *  - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to
    + *                                    an existing CCtx.
    + *                                    These parameters will be applied to
    + *                                    all subsequent compression jobs.
      *  - ZSTD_compress_generic() : Do compression using the CCtx.
      *  - ZSTD_freeCCtxParams() : Free the memory.
      *
    - *  This can be used with ZSTD_estimateCCtxSize_opaque() for static allocation
    - *  for single-threaded compression.
    + *  This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams()
    + *  for static allocation for single-threaded compression.
      */
     ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
     
    @@ -1202,22 +1212,96 @@ ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);
      *  Set one compression parameter, selected by enum ZSTD_cParameter.
      *  Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams().
      *  Note : when `value` is an enum, cast it to unsigned for proper type checking.
    - *  @result : 0, or an error code (which can be tested with ZSTD_isError()).
    + * @result : 0, or an error code (which can be tested with ZSTD_isError()).
      */
     ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value);
     
     /*! ZSTD_CCtx_setParametersUsingCCtxParams() :
    - * Apply a set of ZSTD_CCtx_params to the compression context.
    - * This must be done before the dictionary is loaded.
    - * The pledgedSrcSize is treated as unknown.
    - * Multithreading parameters are applied only if nbThreads > 1.
    + *  Apply a set of ZSTD_CCtx_params to the compression context.
    + *  This must be done before the dictionary is loaded.
    + *  The pledgedSrcSize is treated as unknown.
    + *  Multithreading parameters are applied only if nbThreads > 1.
      */
     ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
             ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
     
    -/**
    -    Block functions
     
    +/*===   Advanced parameters for decompression API  ===*/
    +
    +/* The following parameters must be set after creating a ZSTD_DCtx* (or ZSTD_DStream*) object,
    + * but before starting decompression of a frame.
    + */
    +
    +/*! ZSTD_DCtx_loadDictionary() :
    + *  Create an internal DDict from dict buffer,
    + *  to be used to decompress next frames.
    + * @result : 0, or an error code (which can be tested with ZSTD_isError()).
    + *  Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary,
    + *            meaning "return to no-dictionary mode".
    + *  Note 1 : `dict` content will be copied internally.
    + *            Use ZSTD_DCtx_loadDictionary_byReference()
    + *            to reference dictionary content instead.
    + *            In which case, the dictionary buffer must outlive its users.
    + *  Note 2 : Loading a dictionary involves building tables,
    + *           which has a non-negligible impact on CPU usage and latency.
    + *  Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to select
    + *           how dictionary content will be interpreted and loaded.
    + */
    +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
    +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
    +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode);
    +
    +
    +/*! ZSTD_DCtx_refDDict() :
    + *  Reference a prepared dictionary, to be used to decompress next frames.
    + *  The dictionary remains active for decompression of future frames using same DCtx.
    + * @result : 0, or an error code (which can be tested with ZSTD_isError()).
    + *  Note 1 : Currently, only one dictionary can be managed.
    + *           Referencing a new dictionary effectively "discards" any previous one.
    + *  Special : adding a NULL DDict means "return to no-dictionary mode".
    + *  Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx.
    + */
    +ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
    +
    +
    +/*! ZSTD_DCtx_refPrefix() :
    + *  Reference a prefix (single-usage dictionary) for next compression job.
    + *  Prefix is **only used once**. It must be explicitly referenced before each frame.
    + *  If there is a need to use same prefix multiple times, consider embedding it into a ZSTD_DDict instead.
    + * @result : 0, or an error code (which can be tested with ZSTD_isError()).
    + *  Note 1 : Adding any prefix (including NULL) invalidates any previously set prefix or dictionary
    + *  Note 2 : Prefix buffer is referenced. It must outlive compression job.
    + *  Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent).
    + *           Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode.
    + *  Note 4 : Referencing a raw content prefix costs almost nothing cpu and memory wise.
    + */
    +ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize);
    +ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode);
    +
    +
    +/*! ZSTD_DCtx_setMaxWindowSize() :
    + *  Refuses allocating internal buffers for frames requiring a window size larger than provided limit.
    + *  This is useful to prevent a decoder context from reserving too much memory for itself (potential attack scenario).
    + *  This parameter is only useful in streaming mode, since no internal buffer is allocated in direct mode.
    + *  By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_MAX)
    + * @return : 0, or an error code (which can be tested using ZSTD_isError()).
    + */
    +ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize);
    +
    +
    +/*! ZSTD_DCtx_setFormat() :
    + *  Instruct the decoder context about what kind of data to decode next.
    + *  This instruction is mandatory to decode data without a fully-formed header,
    + *  such ZSTD_f_zstd1_magicless for example.
    + * @return : 0, or an error code (which can be tested using ZSTD_isError()).
    + */
    +ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
    +
    +
    +
    +/** ===   Block level API  === **/
    +
    +/*!
         Block functions produce and decode raw zstd blocks, without frame metadata.
         Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
         User will have to take in charge required information to regenerate data, such as compressed and content sizes.
    
    From 96f0cde31a33f2abc9f782c3b802126a0d235ab3 Mon Sep 17 00:00:00 2001
    From: Yann Collet 
    Date: Sun, 24 Sep 2017 16:47:02 -0700
    Subject: [PATCH 162/248] minor function rename
    
    ZSTD_estimateCStreamSize_advanced_usingCParams -> ZSTD_estimateCStreamSize_usingCParams
    _usingX is clear.
    _advanced feels redundant
    ---
     doc/zstd_manual.html              | 36 +++++++++++++++----------------
     examples/streaming_memory_usage.c |  4 ++--
     lib/compress/zstd_compress.c      | 24 ++++++++++-----------
     lib/zstd.h                        | 36 +++++++++++++++----------------
     tests/paramgrill.c                |  4 ++--
     tests/zstreamtest.c               | 10 ++++-----
     6 files changed, 57 insertions(+), 57 deletions(-)
    
    diff --git a/doc/zstd_manual.html b/doc/zstd_manual.html
    index 64870229b..1cb083286 100644
    --- a/doc/zstd_manual.html
    +++ b/doc/zstd_manual.html
    @@ -403,29 +403,29 @@ size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
     


    size_t ZSTD_estimateCCtxSize(int compressionLevel);
    -size_t ZSTD_estimateCCtxSize_advanced_usingCParams(ZSTD_compressionParameters cParams);
    -size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params);
    +size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams);
    +size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params);
     size_t ZSTD_estimateDCtxSize(void);
     

    These functions make it possible to estimate memory usage of a future {D,C}Ctx, before its creation. ZSTD_estimateCCtxSize() will provide a budget large enough for any compression level up to selected one. It will also consider src size to be arbitrarily "large", which is worst case. - If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced_usingCParams() can provide a tighter estimation. - ZSTD_estimateCCtxSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - ZSTD_estimateCCtxSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1. + If srcSize is known to always be small, ZSTD_estimateCCtxSize_usingCParams() can provide a tighter estimation. + ZSTD_estimateCCtxSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + ZSTD_estimateCCtxSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1. Note : CCtx estimation is only correct for single-threaded compression


    size_t ZSTD_estimateCStreamSize(int compressionLevel);
    -size_t ZSTD_estimateCStreamSize_advanced_usingCParams(ZSTD_compressionParameters cParams);
    -size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params);
    +size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams);
    +size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params);
     size_t ZSTD_estimateDStreamSize(size_t windowSize);
     size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
     

    ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one. It will also consider src size to be arbitrarily "large", which is worst case. - If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced_usingCParams() can provide a tighter estimation. - ZSTD_estimateCStreamSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - ZSTD_estimateCStreamSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1. + If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation. + ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1. Note : CStream estimation is only correct for single-threaded compression. ZSTD_DStream memory budget depends on window Size. This information can be passed manually, using ZSTD_estimateDStreamSize, @@ -436,8 +436,8 @@ size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);


    typedef enum {
    -    ZSTD_dlm_byCopy = 0,      /* Copy dictionary content internally. */
    -    ZSTD_dlm_byRef,           /* Reference dictionary content -- the dictionary buffer must outlives its users. */
    +    ZSTD_dlm_byCopy = 0,     /**< Copy dictionary content internally */
    +    ZSTD_dlm_byRef,          /**< Reference dictionary content -- the dictionary buffer must outlive its users. */
     } ZSTD_dictLoadMethod_e;
     

    size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel);
    @@ -656,8 +656,8 @@ size_t ZSTD_resetDStream(ZSTD_DStream* zds);  /**< re-use decompression para
     

    Buffer-less and synchronous inner streaming functions

       This is an advanced API, giving full control over buffer management, for users which need direct control over memory.
    -  But it's also a complex one, with many restrictions (documented below).
    -  Prefer using normal streaming API for an easier experience
    +  But it's also a complex one, with several restrictions, documented below.
    +  Prefer normal streaming API for an easier experience.
      
     
    @@ -673,8 +673,8 @@ size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompression para Then, consume your input using ZSTD_compressContinue(). There are some important considerations to keep in mind when using this advanced function : - - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffer only. - - Interface is synchronous : input is consumed entirely and produce 1+ (or more) compressed blocks. + - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only. + - Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks. - Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario. Worst case evaluation is provided by ZSTD_compressBound(). ZSTD_compressContinue() doesn't guarantee recover after a failed compression. @@ -685,9 +685,9 @@ size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompression para Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum. It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame. - Without last block mark, frames will be considered unfinished (corrupted) by decoders. + Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders. - `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress some new frame. + `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again.

    Buffer-less streaming compression functions

    size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);
    diff --git a/examples/streaming_memory_usage.c b/examples/streaming_memory_usage.c
    index b709f50bd..b056c2a59 100644
    --- a/examples/streaming_memory_usage.c
    +++ b/examples/streaming_memory_usage.c
    @@ -85,7 +85,7 @@ int main(int argc, char const *argv[]) {
                     return 1;
                 }
             }
    -        
    +
             size_t compressedSize;
             {   ZSTD_inBuffer inBuff = { dataToCompress, sizeof(dataToCompress), 0 };
                 ZSTD_outBuffer outBuff = { compressedData, sizeof(compressedData), 0 };
    @@ -133,7 +133,7 @@ int main(int argc, char const *argv[]) {
     
             size_t const cstreamSize = ZSTD_sizeof_CStream(cstream);
             size_t const cstreamEstimatedSize = wLog ?
    -                ZSTD_estimateCStreamSize_advanced_usingCParams(params.cParams) :
    +                ZSTD_estimateCStreamSize_usingCParams(params.cParams) :
                     ZSTD_estimateCStreamSize(compressionLevel);
             size_t const dstreamSize = ZSTD_sizeof_DStream(dstream);
     
    diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
    index 88eb51dcb..abb27961b 100644
    --- a/lib/compress/zstd_compress.c
    +++ b/lib/compress/zstd_compress.c
    @@ -673,7 +673,7 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u
         return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
     }
     
    -size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params)
    +size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
     {
         /* Estimate CCtx size is supported for single-threaded compression only. */
         if (params->nbThreads > 1) { return ERROR(GENERIC); }
    @@ -710,22 +710,22 @@ size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* pa
         }
     }
     
    -size_t ZSTD_estimateCCtxSize_advanced_usingCParams(ZSTD_compressionParameters cParams)
    +size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
     {
         ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
    -    return ZSTD_estimateCCtxSize_advanced_usingCCtxParams(¶ms);
    +    return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms);
     }
     
     size_t ZSTD_estimateCCtxSize(int compressionLevel)
     {
         ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
    -    return ZSTD_estimateCCtxSize_advanced_usingCParams(cParams);
    +    return ZSTD_estimateCCtxSize_usingCParams(cParams);
     }
     
    -size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params)
    +size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
     {
         if (params->nbThreads > 1) { return ERROR(GENERIC); }
    -    {   size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced_usingCCtxParams(params);
    +    {   size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
             size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog);
             size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize;
             size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
    @@ -735,15 +735,15 @@ size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params*
         }
     }
     
    -size_t ZSTD_estimateCStreamSize_advanced_usingCParams(ZSTD_compressionParameters cParams)
    +size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
     {
         ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
    -    return ZSTD_estimateCStreamSize_advanced_usingCCtxParams(¶ms);
    +    return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms);
     }
     
     size_t ZSTD_estimateCStreamSize(int compressionLevel) {
         ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
    -    return ZSTD_estimateCStreamSize_advanced_usingCParams(cParams);
    +    return ZSTD_estimateCStreamSize_usingCParams(cParams);
     }
     
     static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
    @@ -2182,8 +2182,8 @@ size_t ZSTD_estimateCDictSize_advanced(
     {
         DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict));
         DEBUGLOG(5, "CCtx estimate : %u",
    -             (U32)ZSTD_estimateCCtxSize_advanced_usingCParams(cParams));
    -    return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced_usingCParams(cParams)
    +             (U32)ZSTD_estimateCCtxSize_usingCParams(cParams));
    +    return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_usingCParams(cParams)
                + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
     }
     
    @@ -2308,7 +2308,7 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
                                      ZSTD_dictMode_e dictMode,
                                      ZSTD_compressionParameters cParams)
     {
    -    size_t const cctxSize = ZSTD_estimateCCtxSize_advanced_usingCParams(cParams);
    +    size_t const cctxSize = ZSTD_estimateCCtxSize_usingCParams(cParams);
         size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize)
                                 + cctxSize;
         ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
    diff --git a/lib/zstd.h b/lib/zstd.h
    index 655fa29d3..047f905b7 100644
    --- a/lib/zstd.h
    +++ b/lib/zstd.h
    @@ -499,21 +499,21 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
      *  of a future {D,C}Ctx, before its creation.
      *  ZSTD_estimateCCtxSize() will provide a budget large enough for any compression level up to selected one.
      *  It will also consider src size to be arbitrarily "large", which is worst case.
    - *  If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced_usingCParams() can provide a tighter estimation.
    - *  ZSTD_estimateCCtxSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
    - *  ZSTD_estimateCCtxSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1.
    + *  If srcSize is known to always be small, ZSTD_estimateCCtxSize_usingCParams() can provide a tighter estimation.
    + *  ZSTD_estimateCCtxSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
    + *  ZSTD_estimateCCtxSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1.
      *  Note : CCtx estimation is only correct for single-threaded compression */
     ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel);
    -ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced_usingCParams(ZSTD_compressionParameters cParams);
    -ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params);
    +ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams);
    +ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params);
     ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void);
     
     /*! ZSTD_estimateCStreamSize() :
      *  ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one.
      *  It will also consider src size to be arbitrarily "large", which is worst case.
    - *  If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced_usingCParams() can provide a tighter estimation.
    - *  ZSTD_estimateCStreamSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
    - *  ZSTD_estimateCStreamSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1.
    + *  If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
    + *  ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
    + *  ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1.
      *  Note : CStream estimation is only correct for single-threaded compression.
      *  ZSTD_DStream memory budget depends on window Size.
      *  This information can be passed manually, using ZSTD_estimateDStreamSize,
    @@ -522,14 +522,14 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void);
      *         an internal ?Dict will be created, which additional size is not estimated here.
      *         In this case, get total size by adding ZSTD_estimate?DictSize */
     ZSTDLIB_API size_t ZSTD_estimateCStreamSize(int compressionLevel);
    -ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced_usingCParams(ZSTD_compressionParameters cParams);
    -ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params);
    +ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams);
    +ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params);
     ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize);
     ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
     
     typedef enum {
    -    ZSTD_dlm_byCopy = 0,      /* Copy dictionary content internally. */
    -    ZSTD_dlm_byRef,           /* Reference dictionary content -- the dictionary buffer must outlives its users. */
    +    ZSTD_dlm_byCopy = 0,     /**< Copy dictionary content internally */
    +    ZSTD_dlm_byRef,          /**< Reference dictionary content -- the dictionary buffer must outlive its users. */
     } ZSTD_dictLoadMethod_e;
     
     /*! ZSTD_estimate?DictSize() :
    @@ -760,8 +760,8 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);  /**< re-use decompress
     *  Buffer-less and synchronous inner streaming functions
     *
     *  This is an advanced API, giving full control over buffer management, for users which need direct control over memory.
    -*  But it's also a complex one, with many restrictions (documented below).
    -*  Prefer using normal streaming API for an easier experience
    +*  But it's also a complex one, with several restrictions, documented below.
    +*  Prefer normal streaming API for an easier experience.
     ********************************************************************* */
     
     /**
    @@ -778,8 +778,8 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);  /**< re-use decompress
     
       Then, consume your input using ZSTD_compressContinue().
       There are some important considerations to keep in mind when using this advanced function :
    -  - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffer only.
    -  - Interface is synchronous : input is consumed entirely and produce 1+ (or more) compressed blocks.
    +  - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only.
    +  - Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks.
       - Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario.
         Worst case evaluation is provided by ZSTD_compressBound().
         ZSTD_compressContinue() doesn't guarantee recover after a failed compression.
    @@ -790,9 +790,9 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);  /**< re-use decompress
     
       Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum.
       It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame.
    -  Without last block mark, frames will be considered unfinished (corrupted) by decoders.
    +  Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders.
     
    -  `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress some new frame.
    +  `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again.
     */
     
     /*=====   Buffer-less streaming compression functions  =====*/
    diff --git a/tests/paramgrill.c b/tests/paramgrill.c
    index 1bc48f401..317ec461c 100644
    --- a/tests/paramgrill.c
    +++ b/tests/paramgrill.c
    @@ -391,8 +391,8 @@ static int BMK_seed(winnerInfo_t* winners, const ZSTD_compressionParameters para
                 double W_DMemUsed_note = W_ratioNote * ( 40 + 9*cLevel) - log((double)W_DMemUsed);
                 double O_DMemUsed_note = O_ratioNote * ( 40 + 9*cLevel) - log((double)O_DMemUsed);
     
    -            size_t W_CMemUsed = (1 << params.windowLog) + ZSTD_estimateCCtxSize_advanced_usingCParams(params);
    -            size_t O_CMemUsed = (1 << winners[cLevel].params.windowLog) + ZSTD_estimateCCtxSize_advanced_usingCParams(winners[cLevel].params);
    +            size_t W_CMemUsed = (1 << params.windowLog) + ZSTD_estimateCCtxSize_usingCParams(params);
    +            size_t O_CMemUsed = (1 << winners[cLevel].params.windowLog) + ZSTD_estimateCCtxSize_usingCParams(winners[cLevel].params);
                 double W_CMemUsed_note = W_ratioNote * ( 50 + 13*cLevel) - log((double)W_CMemUsed);
                 double O_CMemUsed_note = O_ratioNote * ( 50 + 13*cLevel) - log((double)O_CMemUsed);
     
    diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c
    index e52335da0..613a879bf 100644
    --- a/tests/zstreamtest.c
    +++ b/tests/zstreamtest.c
    @@ -200,11 +200,11 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
         /* context size functions */
         DISPLAYLEVEL(3, "test%3i : estimate CStream size : ", testNb++);
         {   ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictSize);
    -        size_t const s = ZSTD_estimateCStreamSize_advanced_usingCParams(cParams)
    -                        /* uses ZSTD_initCStream_usingDict() */
    -                       + ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
    -            if (ZSTD_isError(s)) goto _output_error;
    -            DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)s);
    +        size_t const cstreamSize = ZSTD_estimateCStreamSize_usingCParams(cParams);
    +        size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); /* uses ZSTD_initCStream_usingDict() */
    +        if (ZSTD_isError(cstreamSize)) goto _output_error;
    +        if (ZSTD_isError(cdictSize)) goto _output_error;
    +        DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)(cstreamSize + cdictSize));
         }
     
         DISPLAYLEVEL(3, "test%3i : check actual CStream size : ", testNb++);
    
    From 1c23b640499c1539df0bd30b833d31b50eac442a Mon Sep 17 00:00:00 2001
    From: Nick Terrell 
    Date: Mon, 25 Sep 2017 11:27:33 -0700
    Subject: [PATCH 163/248] [fuzz] fuzz.py can minimize and zip corpora
    
    * "minimize" minimizes the corpora into an output directory.
    * "zip" zips up the minimized corpora, which are ready to deploy.
    ---
     tests/fuzz/fuzz.py | 165 +++++++++++++++++++++++++++++++--------------
     1 file changed, 114 insertions(+), 51 deletions(-)
    
    diff --git a/tests/fuzz/fuzz.py b/tests/fuzz/fuzz.py
    index 0ce201cdd..8c381ecf8 100755
    --- a/tests/fuzz/fuzz.py
    +++ b/tests/fuzz/fuzz.py
    @@ -82,6 +82,35 @@ def tmpdir():
             shutil.rmtree(dirpath, ignore_errors=True)
     
     
    +def parse_targets(in_targets):
    +    targets = set()
    +    for target in in_targets:
    +        if not target:
    +            continue
    +        if target == 'all':
    +            targets = targets.union(TARGETS)
    +        elif target in TARGETS:
    +            targets.add(target)
    +        else:
    +            raise RuntimeError('{} is not a valid target'.format(target))
    +    return list(targets)
    +
    +
    +def targets_parser(args, description):
    +    parser = argparse.ArgumentParser(prog=args.pop(0), description=description)
    +    parser.add_argument(
    +        'TARGET',
    +        nargs='*',
    +        type=str,
    +        help='Fuzz target(s) to build {{{}}}'.format(', '.join(ALL_TARGETS)))
    +    args, extra = parser.parse_known_args(args)
    +    args.extra = extra
    +
    +    args.TARGET = parse_targets(args.TARGET)
    +
    +    return args
    +
    +
     def parse_env_flags(args, flags):
         """
         Look for flags set by environment variables.
    @@ -424,36 +453,42 @@ def libfuzzer_parser(args):
         if args.TARGET and args.TARGET not in TARGETS:
             raise RuntimeError('{} is not a valid target'.format(args.TARGET))
     
    -    if not args.corpora:
    -        args.corpora = abs_join(CORPORA_DIR, args.TARGET)
    -    if not args.artifact:
    -        args.artifact = abs_join(CORPORA_DIR, '{}-crash'.format(args.TARGET))
    -    if not args.seed:
    -        args.seed = abs_join(CORPORA_DIR, '{}-seed'.format(args.TARGET))
    -
         return args
     
     
    -def libfuzzer(args):
    -    try:
    -        args = libfuzzer_parser(args)
    -    except Exception as e:
    -        print(e)
    -        return 1
    -    target = abs_join(FUZZ_DIR, args.TARGET)
    +def libfuzzer(target, corpora=None, artifact=None, seed=None, extra_args=None):
    +    if corpora is None:
    +        corpora = abs_join(CORPORA_DIR, target)
    +    if artifact is None:
    +        artifact = abs_join(CORPORA_DIR, '{}-crash'.format(target))
    +    if seed is None:
    +        seed = abs_join(CORPORA_DIR, '{}-seed'.format(target))
    +    if extra_args is None:
    +        extra_args = []
     
    -    corpora = [create(args.corpora)]
    -    artifact = create(args.artifact)
    -    seed = check(args.seed)
    +    target = abs_join(FUZZ_DIR, target)
    +
    +    corpora = [create(corpora)]
    +    artifact = create(artifact)
    +    seed = check(seed)
     
         corpora += [artifact]
         if seed is not None:
             corpora += [seed]
     
         cmd = [target, '-artifact_prefix={}/'.format(artifact)]
    -    cmd += corpora + args.extra
    +    cmd += corpora + extra_args
         print(' '.join(cmd))
    -    subprocess.call(cmd)
    +    subprocess.check_call(cmd)
    +
    +
    +def libfuzzer_cmd(args):
    +    try:
    +        args = libfuzzer_parser(args)
    +    except Exception as e:
    +        print(e)
    +        return 1
    +    libfuzzer(args.TARGET, args.corpora, args.artifact, args.seed, args.extra)
         return 0
     
     
    @@ -518,39 +553,15 @@ def afl(args):
         return 0
     
     
    -def regression_parser(args):
    -    description = """
    -    Runs one or more regression tests.
    -    The fuzzer should have been built with with
    -    LIB_FUZZING_ENGINE='libregression.a'.
    -    Takes input from CORPORA.
    -    """
    -    parser = argparse.ArgumentParser(prog=args.pop(0), description=description)
    -    parser.add_argument(
    -        'TARGET',
    -        nargs='*',
    -        type=str,
    -        help='Fuzz target(s) to build {{{}}}'.format(', '.join(ALL_TARGETS)))
    -    args = parser.parse_args(args)
    -
    -    targets = set()
    -    for target in args.TARGET:
    -        if not target:
    -            continue
    -        if target == 'all':
    -            targets = targets.union(TARGETS)
    -        elif target in TARGETS:
    -            targets.add(target)
    -        else:
    -            raise RuntimeError('{} is not a valid target'.format(target))
    -    args.TARGET = list(targets)
    -
    -    return args
    -
    -
     def regression(args):
         try:
    -        args = regression_parser(args)
    +        description = """
    +        Runs one or more regression tests.
    +        The fuzzer should have been built with with
    +        LIB_FUZZING_ENGINE='libregression.a'.
    +        Takes input from CORPORA.
    +        """
    +        args = targets_parser(args, description)
         except Exception as e:
             print(e)
             return 1
    @@ -673,6 +684,52 @@ def gen(args):
         return 0
     
     
    +def minimize(args):
    +    try:
    +        description = """
    +        Runs a libfuzzer fuzzer with -merge=1 to build a minimal corpus in
    +        TARGET_seed_corpus. All extra args are passed to libfuzzer.
    +        """
    +        args = targets_parser(args, description)
    +    except Exception as e:
    +        print(e)
    +        return 1
    +
    +    for target in args.TARGET:
    +        # Merge the corpus + anything else into the seed_corpus
    +        corpus = abs_join(CORPORA_DIR, target)
    +        seed_corpus = abs_join(CORPORA_DIR, "{}_seed_corpus".format(target))
    +        extra_args = [corpus, "-merge=1"] + args.extra
    +        libfuzzer(target, corpora=seed_corpus, extra_args=extra_args)
    +        seeds = set(os.listdir(seed_corpus))
    +        # Copy all crashes directly into the seed_corpus if not already present
    +        crashes = abs_join(CORPORA_DIR, '{}-crash'.format(target))
    +        for crash in os.listdir(crashes):
    +            if crash not in seeds:
    +                shutil.copy(abs_join(crashes, crash), seed_corpus)
    +                seeds.add(crash)
    +
    +
    +def zip_cmd(args):
    +    try:
    +        description = """
    +        Zips up the seed corpus.
    +        """
    +        args = targets_parser(args, description)
    +    except Exception as e:
    +        print(e)
    +        return 1
    +
    +    for target in args.TARGET:
    +        # Zip the seed_corpus
    +        seed_corpus = abs_join(CORPORA_DIR, "{}_seed_corpus".format(target))
    +        seeds = [abs_join(seed_corpus, f) for f in os.listdir(seed_corpus)]
    +        zip_file = "{}.zip".format(seed_corpus)
    +        cmd = ["zip", "-q", "-j", "-9", zip_file]
    +        print(' '.join(cmd + [abs_join(seed_corpus, '*')]))
    +        subprocess.check_call(cmd + seeds)
    +
    +
     def short_help(args):
         name = args[0]
         print("Usage: {} [OPTIONS] COMMAND [ARGS]...\n".format(name))
    @@ -690,6 +747,8 @@ def help(args):
         print("\tafl\t\tRun an AFL fuzzer")
         print("\tregression\tRun a regression test")
         print("\tgen\t\tGenerate a seed corpus for a fuzzer")
    +    print("\tminimize\tMinimize the test corpora")
    +    print("\tzip\t\tZip the minimized corpora up")
     
     
     def main():
    @@ -705,13 +764,17 @@ def main():
         if command == "build":
             return build(args)
         if command == "libfuzzer":
    -        return libfuzzer(args)
    +        return libfuzzer_cmd(args)
         if command == "regression":
             return regression(args)
         if command == "afl":
             return afl(args)
         if command == "gen":
             return gen(args)
    +    if command == "minimize":
    +        return minimize(args)
    +    if command == "zip":
    +        return zip_cmd(args)
         short_help(args)
         print("Error: No such command {} (pass -h for help)".format(command))
         return 1
    
    From 23199b6daf4757b41b20fc83d95f5f4b50bad948 Mon Sep 17 00:00:00 2001
    From: Nick Terrell 
    Date: Mon, 25 Sep 2017 13:28:18 -0700
    Subject: [PATCH 164/248] [fuzz] Fix fuzz.py env flags parsing
    
    ---
     tests/fuzz/fuzz.py | 1 -
     1 file changed, 1 deletion(-)
    
    diff --git a/tests/fuzz/fuzz.py b/tests/fuzz/fuzz.py
    index 8c381ecf8..cd4087090 100755
    --- a/tests/fuzz/fuzz.py
    +++ b/tests/fuzz/fuzz.py
    @@ -115,7 +115,6 @@ def parse_env_flags(args, flags):
         """
         Look for flags set by environment variables.
         """
    -    flags = ' '.join(flags)
         san_flags = ','.join(re.findall('-fsanitize=((?:[a-z]+,?)+)', flags))
         nosan_flags = ','.join(re.findall('-fno-sanitize=((?:[a-z]+,?)+)', flags))
     
    
    From bfad5568b5318adf6766de6deaaf4f9b0cc1c668 Mon Sep 17 00:00:00 2001
    From: Nick Terrell 
    Date: Mon, 25 Sep 2017 13:28:45 -0700
    Subject: [PATCH 165/248] [fuzz] Make simple_round_trip compile cleanly
    
    ---
     tests/fuzz/simple_round_trip.c | 3 ++-
     1 file changed, 2 insertions(+), 1 deletion(-)
    
    diff --git a/tests/fuzz/simple_round_trip.c b/tests/fuzz/simple_round_trip.c
    index f853485ad..617e45df6 100644
    --- a/tests/fuzz/simple_round_trip.c
    +++ b/tests/fuzz/simple_round_trip.c
    @@ -38,10 +38,11 @@ static size_t roundTripTest(void *result, size_t resultCapacity,
         if (FUZZ_rand(&seed) & 1) {
             ZSTD_inBuffer in = {src, srcSize, 0};
             ZSTD_outBuffer out = {compressed, compressedCapacity, 0};
    +        size_t err;
     
             ZSTD_CCtx_reset(cctx);
             FUZZ_setRandomParameters(cctx, &seed);
    -        size_t const err = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end);
    +        err = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end);
             if (err != 0) {
                 return err;
             }
    
    From bbe77212efebcfefb6b510f2509a674a5dd25245 Mon Sep 17 00:00:00 2001
    From: Nick Terrell 
    Date: Mon, 18 Sep 2017 16:54:53 -0700
    Subject: [PATCH 166/248] [libzstd] Increase MaxOff
    
    ---
     lib/common/zstd_internal.h       |  7 +++--
     lib/compress/zstd_compress.c     | 33 ++++++++++++++------
     lib/decompress/zstd_decompress.c | 53 ++++++++++++++++++++++----------
     tests/decodecorpus.c             |  2 +-
     4 files changed, 65 insertions(+), 30 deletions(-)
    
    diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h
    index cd0dbcc27..403c0cbdb 100644
    --- a/lib/common/zstd_internal.h
    +++ b/lib/common/zstd_internal.h
    @@ -123,7 +123,8 @@ typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingTy
     #define MaxLit ((1<longLengthPos] = MaxML;
     }
     
    -MEM_STATIC symbolEncodingType_e ZSTD_selectEncodingType(FSE_repeat* repeatMode,
    -        size_t const mostFrequent, size_t nbSeq, U32 defaultNormLog)
    +typedef enum {
    +    ZSTD_defaultDisallowed = 0,
    +    ZSTD_defaultAllowed = 1
    +} ZSTD_defaultPolicy_e;
    +
    +MEM_STATIC symbolEncodingType_e ZSTD_selectEncodingType(
    +        FSE_repeat* repeatMode, size_t const mostFrequent, size_t nbSeq,
    +        U32 defaultNormLog, ZSTD_defaultPolicy_e const isDefaultAllowed)
     {
     #define MIN_SEQ_FOR_DYNAMIC_FSE   64
     #define MAX_SEQ_FOR_STATIC_FSE  1000
    -
    -    if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
    +    ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0);
    +    if ((mostFrequent == nbSeq) && (!isDefaultAllowed || nbSeq > 2)) {
    +        /* Prefer set_basic over set_rle when there are 2 or less symbols,
    +         * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
    +         * If basic encoding isn't possible, always choose RLE.
    +         */
             *repeatMode = FSE_repeat_check;
             return set_rle;
         }
    -    if ((*repeatMode == FSE_repeat_valid) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
    +    if (isDefaultAllowed && (*repeatMode == FSE_repeat_valid) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
             return set_repeat;
         }
    -    if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (defaultNormLog-1)))) {
    +    if (isDefaultAllowed && ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (defaultNormLog-1))))) {
             *repeatMode = FSE_repeat_valid;
             return set_basic;
         }
    @@ -1299,6 +1309,7 @@ MEM_STATIC size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
                 count[codeTable[nbSeq-1]]--;
                 nbSeq_1--;
             }
    +        assert(nbSeq_1 > 1);
             CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max));
             {   size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog);   /* overflow protected */
                 if (FSE_isError(NCountSize)) return NCountSize;
    @@ -1436,7 +1447,7 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
         /* CTable for Literal Lengths */
         {   U32 max = MaxLL;
             size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, entropy->workspace);
    -        LLtype = ZSTD_selectEncodingType(&entropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog);
    +        LLtype = ZSTD_selectEncodingType(&entropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog, ZSTD_defaultAllowed);
             {   size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
                         count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
                         entropy->workspace, sizeof(entropy->workspace));
    @@ -1446,9 +1457,11 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
         /* CTable for Offsets */
         {   U32 max = MaxOff;
             size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, entropy->workspace);
    -        Offtype = ZSTD_selectEncodingType(&entropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog);
    +        /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
    +        ZSTD_defaultPolicy_e const defaultPolicy = max <= DefaultMaxOff ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
    +        Offtype = ZSTD_selectEncodingType(&entropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog, defaultPolicy);
             {   size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
    -                    count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, MaxOff,
    +                    count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
                         entropy->workspace, sizeof(entropy->workspace));
                 if (ZSTD_isError(countSize)) return countSize;
                 op += countSize;
    @@ -1456,7 +1469,7 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
         /* CTable for MatchLengths */
         {   U32 max = MaxML;
             size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, entropy->workspace);
    -        MLtype = ZSTD_selectEncodingType(&entropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog);
    +        MLtype = ZSTD_selectEncodingType(&entropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog, ZSTD_defaultAllowed);
             {   size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
                         count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
                         entropy->workspace, sizeof(entropy->workspace));
    diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c
    index 6d6d83396..b6bfa0c49 100644
    --- a/lib/decompress/zstd_decompress.c
    +++ b/lib/decompress/zstd_decompress.c
    @@ -862,6 +862,15 @@ size_t ZSTD_execSequenceLast7(BYTE* op,
     
     typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e;
     
    +/* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum
    + * offset bits. But we can only read at most (STREAM_ACCUMULATOR_MIN_32 - 1)
    + * bits before reloading. This value is the maximum number of bytes we read
    + * after reloading when we are decoding long offets.
    + */
    +#define LONG_OFFSETS_MAX_EXTRA_BITS_32                                         \
    +    (ZSTD_WINDOWLOG_MAX_32 > STREAM_ACCUMULATOR_MIN_32                         \
    +        ? ZSTD_WINDOWLOG_MAX_32 - STREAM_ACCUMULATOR_MIN_32                    \
    +        : 0)
     
     static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets)
     {
    @@ -869,7 +878,7 @@ static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e l
     
         U32 const llCode = FSE_peekSymbol(&seqState->stateLL);
         U32 const mlCode = FSE_peekSymbol(&seqState->stateML);
    -    U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb);   /* <= maxOff, by table construction */
    +    U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb);   /* <= MaxOff, by table construction */
     
         U32 const llBits = LL_bits[llCode];
         U32 const mlBits = ML_bits[mlCode];
    @@ -896,7 +905,7 @@ static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e l
                          0,        1,       1,       5,     0xD,     0x1D,     0x3D,     0x7D,
                          0xFD,   0x1FD,   0x3FD,   0x7FD,   0xFFD,   0x1FFD,   0x3FFD,   0x7FFD,
                          0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
    -                     0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD };
    +                     0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD };
     
         /* sequence */
         {   size_t offset;
    @@ -904,8 +913,10 @@ static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e l
                 offset = 0;
             else {
                 ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
    -            if (longOffsets) {
    -                int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN);
    +            ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 2);
    +            assert(ofBits <= MaxOff);
    +            if (MEM_32bits() && longOffsets) {
    +                U32 const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN_32-1);
                     offset = OF_base[ofCode] + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
                     if (MEM_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream);
                     if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
    @@ -936,13 +947,17 @@ static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e l
     
         seq.matchLength = ML_base[mlCode]
                         + ((mlCode>31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0);  /* <=  16 bits */
    -    if (MEM_32bits() && (mlBits+llBits>24)) BIT_reloadDStream(&seqState->DStream);
    +    if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
    +        BIT_reloadDStream(&seqState->DStream);
    +    if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
    +        BIT_reloadDStream(&seqState->DStream);
    +    /* Verify that there is enough bits to read the rest of the data in 64-bit mode. */
    +    ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
     
         seq.litLength = LL_base[llCode]
                       + ((llCode>15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0);    /* <=  16 bits */
    -    if (  MEM_32bits()
    -      || (totalBits > 64 - 7 - (LLFSELog+MLFSELog+OffFSELog)) )
    -       BIT_reloadDStream(&seqState->DStream);
    +    if (MEM_32bits())
    +        BIT_reloadDStream(&seqState->DStream);
     
         DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u",
                     (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
    @@ -1102,7 +1117,6 @@ static size_t ZSTD_decompressSequences(
     }
     
     
    -
     HINT_INLINE
     seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const longOffsets)
     {
    @@ -1110,7 +1124,7 @@ seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const long
     
         U32 const llCode = FSE_peekSymbol(&seqState->stateLL);
         U32 const mlCode = FSE_peekSymbol(&seqState->stateML);
    -    U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb);   /* <= maxOff, by table construction */
    +    U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb);   /* <= MaxOff, by table construction */
     
         U32 const llBits = LL_bits[llCode];
         U32 const mlBits = ML_bits[mlCode];
    @@ -1137,7 +1151,7 @@ seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const long
                          0,        1,       1,       5,     0xD,     0x1D,     0x3D,     0x7D,
                          0xFD,   0x1FD,   0x3FD,   0x7FD,   0xFFD,   0x1FFD,   0x3FFD,   0x7FFD,
                          0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
    -                     0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD };
    +                     0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD };
     
         /* sequence */
         {   size_t offset;
    @@ -1145,8 +1159,10 @@ seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const long
                 offset = 0;
             else {
                 ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
    -            if (longOffsets) {
    -                int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN);
    +            ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 2);
    +            assert(ofBits <= MaxOff);
    +            if (MEM_32bits() && longOffsets) {
    +                U32 const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN_32-1);
                     offset = OF_base[ofCode] + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
                     if (MEM_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream);
                     if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
    @@ -1176,11 +1192,16 @@ seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const long
         }
     
         seq.matchLength = ML_base[mlCode] + ((mlCode>31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0);  /* <=  16 bits */
    -    if (MEM_32bits() && (mlBits+llBits>24)) BIT_reloadDStream(&seqState->DStream);
    +    if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
    +        BIT_reloadDStream(&seqState->DStream);
    +    if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
    +        BIT_reloadDStream(&seqState->DStream);
    +    /* Verify that there is enough bits to read the rest of the data in 64-bit mode. */
    +    ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
     
         seq.litLength = LL_base[llCode] + ((llCode>15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0);    /* <=  16 bits */
    -    if (MEM_32bits() ||
    -       (totalBits > 64 - 7 - (LLFSELog+MLFSELog+OffFSELog)) ) BIT_reloadDStream(&seqState->DStream);
    +    if (MEM_32bits())
    +        BIT_reloadDStream(&seqState->DStream);
     
         {   size_t const pos = seqState->pos + seq.litLength;
             seq.match = seqState->base + pos - seq.offset;    /* single memory segment */
    diff --git a/tests/decodecorpus.c b/tests/decodecorpus.c
    index 9cde2825e..ea01d2718 100644
    --- a/tests/decodecorpus.c
    +++ b/tests/decodecorpus.c
    @@ -881,7 +881,7 @@ static size_t writeSequences(U32* seed, frame_t* frame, seqStore_t* seqStorePtr,
                                       frame->stats.offsetSymbolSet, 28)) {
                 Offtype = set_repeat;
             } else if (!(RAND(seed) & 3)) {
    -            FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
    +            FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, DefaultMaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
                 Offtype = set_basic;
             } else {
                 size_t nbSeq_1 = nbSeq;
    
    From 62568c9a426316a063c70e4f1eb1241eaad83fec Mon Sep 17 00:00:00 2001
    From: Yann Collet 
    Date: Mon, 25 Sep 2017 14:26:26 -0700
    Subject: [PATCH 167/248] added capability to generate magic-less frames
    
    decoder not implemented yet
    ---
     lib/compress/zstd_compress.c     |  12 ++-
     lib/decompress/zstd_decompress.c | 134 +++++++++++++++++++++++--------
     lib/zstd.h                       |  28 +++++--
     programs/Makefile                |   2 +-
     programs/fileio.c                |   2 +-
     tests/fuzzer.c                   |  39 ++++++++-
     tests/playTests.sh               |   6 +-
     7 files changed, 172 insertions(+), 51 deletions(-)
    
    diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
    index abb27961b..16137bb74 100644
    --- a/lib/compress/zstd_compress.c
    +++ b/lib/compress/zstd_compress.c
    @@ -1690,14 +1690,18 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
         U32   const fcsCode = params.fParams.contentSizeFlag ?
                          (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0;  /* 0-3 */
         BYTE  const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
    -    size_t pos;
    +    size_t pos=0;
     
         if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
    -    DEBUGLOG(5, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
    +    DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
                     !params.fParams.noDictIDFlag, dictID,  dictIDSizeCode);
     
    -    MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
    -    op[4] = frameHeaderDecriptionByte; pos=5;
    +    if (params.format == ZSTD_f_zstd1) {
    +        DEBUGLOG(4, "writing zstd magic number");
    +        MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
    +        pos = 4;
    +    }
    +    op[pos++] = frameHeaderDecriptionByte;
         if (!singleSegment) op[pos++] = windowLogByte;
         switch(dictIDSizeCode)
         {
    diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c
    index cd64f3bbb..47627037b 100644
    --- a/lib/decompress/zstd_decompress.c
    +++ b/lib/decompress/zstd_decompress.c
    @@ -110,6 +110,7 @@ struct ZSTD_DCtx_s
         XXH64_state_t xxhState;
         size_t headerSize;
         U32 dictID;
    +    ZSTD_format_e format;
         const BYTE* litPtr;
         ZSTD_customMem customMem;
         size_t litSize;
    @@ -264,32 +265,57 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size)
     }
     
     
    -/** ZSTD_frameHeaderSize() :
    -*   srcSize must be >= ZSTD_frameHeaderSize_prefix.
    -*   @return : size of the Frame Header */
    -size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
    +/** ZSTD_frameHeaderSize_internal() :
    + *  srcSize must be large enough to reach header size fields.
    + *  note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
    + * @return : size of the Frame Header
    + *           or an error code, which can be tested with ZSTD_isError() */
    +static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)
     {
    -    if (srcSize < ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong);
    -    {   BYTE const fhd = ((const BYTE*)src)[4];
    +    size_t const minInputSize = (format==ZSTD_f_zstd1_magicless) ?
    +                    ZSTD_frameHeaderSize_prefix - 4 /* magic number size */ :
    +                    ZSTD_frameHeaderSize_prefix;
    +    ZSTD_STATIC_ASSERT((unsigned)ZSTD_f_zstd1 < (unsigned)ZSTD_f_zstd1_magicless);
    +    assert((unsigned)format <= ZSTD_f_zstd1_magicless);  /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */
    +    if (srcSize < minInputSize) return ERROR(srcSize_wrong);
    +
    +    {   BYTE const fhd = ((const BYTE*)src)[minInputSize-1];
             U32 const dictID= fhd & 3;
             U32 const singleSegment = (fhd >> 5) & 1;
             U32 const fcsId = fhd >> 6;
    -        return ZSTD_frameHeaderSize_prefix + !singleSegment + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]
    -                + (singleSegment && !fcsId);
    +        return minInputSize + !singleSegment
    +             + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]
    +             + (singleSegment && !fcsId);
         }
     }
     
    +/** ZSTD_frameHeaderSize() :
    + *  srcSize must be >= ZSTD_frameHeaderSize_prefix.
    + * @return : size of the Frame Header */
    +size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
    +{
    +    return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1);
    +}
     
    -/** ZSTD_getFrameHeader() :
    -*   decode Frame Header, or require larger `srcSize`.
    -*   @return : 0, `zfhPtr` is correctly filled,
    -*            >0, `srcSize` is too small, result is expected `srcSize`,
    -*             or an error code, which can be tested using ZSTD_isError() */
    -size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)
    +
    +/** ZSTD_getFrameHeader_internal() :
    + *  decode Frame Header, or require larger `srcSize`.
    + *  note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
    + * @return : 0, `zfhPtr` is correctly filled,
    + *          >0, `srcSize` is too small, value is wanted `srcSize` amount,
    + *           or an error code, which can be tested using ZSTD_isError() */
    +static size_t ZSTD_getFrameHeader_internal(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)
     {
         const BYTE* ip = (const BYTE*)src;
    -    if (srcSize < ZSTD_frameHeaderSize_prefix) return ZSTD_frameHeaderSize_prefix;
    +    size_t const minInputSize = (format==ZSTD_f_zstd1_magicless) ?
    +                    ZSTD_frameHeaderSize_prefix - 4 /* magic number size */ :
    +                    ZSTD_frameHeaderSize_prefix;
     
    +    ZSTD_STATIC_ASSERT((unsigned)ZSTD_f_zstd1 < (unsigned)ZSTD_f_zstd1_magicless);
    +    assert((unsigned)format <= ZSTD_f_zstd1_magicless);  /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */
    +    if (srcSize < minInputSize) return minInputSize;
    +
    +    if (format != ZSTD_f_zstd1_magicless)
         if (MEM_readLE32(src) != ZSTD_MAGICNUMBER) {
             if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
                 /* skippable frame */
    @@ -304,13 +330,13 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src
         }
     
         /* ensure there is enough `srcSize` to fully read/decode frame header */
    -    {   size_t const fhsize = ZSTD_frameHeaderSize(src, srcSize);
    +    {   size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format);
             if (srcSize < fhsize) return fhsize;
             zfhPtr->headerSize = (U32)fhsize;
         }
     
    -    {   BYTE const fhdByte = ip[4];
    -        size_t pos = 5;
    +    {   BYTE const fhdByte = ip[minInputSize-1];
    +        size_t pos = minInputSize;
             U32 const dictIDSizeCode = fhdByte&3;
             U32 const checksumFlag = (fhdByte>>2)&1;
             U32 const singleSegment = (fhdByte>>5)&1;
    @@ -357,6 +383,18 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src
         return 0;
     }
     
    +/** ZSTD_getFrameHeader() :
    + *  decode Frame Header, or require larger `srcSize`.
    + *  note : this function does not consume input, it only reads it.
    + * @return : 0, `zfhPtr` is correctly filled,
    + *          >0, `srcSize` is too small, value is wanted `srcSize` amount,
    + *           or an error code, which can be tested using ZSTD_isError() */
    +size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)
    +{
    +    return ZSTD_getFrameHeader_internal(zfhPtr, src, srcSize, ZSTD_f_zstd1);
    +}
    +
    +
     /** ZSTD_getFrameContentSize() :
      *  compatible with legacy mode
      * @return : decompressed size of the single frame pointed to be `src` if known, otherwise
    @@ -390,7 +428,7 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
         unsigned long long totalDstSize = 0;
     
         while (srcSize >= ZSTD_frameHeaderSize_prefix) {
    -        const U32 magicNumber = MEM_readLE32(src);
    +        U32 const magicNumber = MEM_readLE32(src);
     
             if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
                 size_t skippableSize;
    @@ -422,11 +460,9 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
                 src = (const BYTE *)src + frameSrcSize;
                 srcSize -= frameSrcSize;
             }
    -    }
    +    }  /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
     
    -    if (srcSize) {
    -        return ZSTD_CONTENTSIZE_ERROR;
    -    }
    +    if (srcSize) return ZSTD_CONTENTSIZE_ERROR;
     
         return totalDstSize;
     }
    @@ -442,7 +478,8 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
     unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
     {
         unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
    -    return ret >= ZSTD_CONTENTSIZE_ERROR ? 0 : ret;
    +    ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN);
    +    return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret;
     }
     
     
    @@ -452,8 +489,8 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
     static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
     {
         size_t const result = ZSTD_getFrameHeader(&(dctx->fParams), src, headerSize);
    -    if (ZSTD_isError(result)) return result;  /* invalid header */
    -    if (result>0) return ERROR(srcSize_wrong);   /* headerSize too small */
    +    if (ZSTD_isError(result)) return result;    /* invalid header */
    +    if (result>0) return ERROR(srcSize_wrong);  /* headerSize too small */
         if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID))
             return ERROR(dictionary_wrong);
         if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0);
    @@ -499,7 +536,7 @@ static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,
     }
     
     /*! ZSTD_decodeLiteralsBlock() :
    -    @return : nb of bytes read from src (< srcSize ) */
    + * @return : nb of bytes read from src (< srcSize ) */
     size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
                               const void* src, size_t srcSize)   /* note : srcSize < BLOCKSIZE */
     {
    @@ -700,9 +737,9 @@ static const FSE_decode_t4 OF_defaultDTable[(1< dstCapacity) return ERROR(dstSize_tooSmall);
         memset(dst, byte, length);
    @@ -1607,6 +1644,8 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
     #endif
     
             magicNumber = MEM_readLE32(src);
    +        DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
    +                    (U32)magicNumber, (U32)ZSTD_MAGICNUMBER);
             if (magicNumber != ZSTD_MAGICNUMBER) {
                 if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
                     size_t skippableSize;
    @@ -1716,7 +1755,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
     {
         DEBUGLOG(5, "ZSTD_decompressContinue");
         /* Sanity check */
    -    if (srcSize != dctx->expected) return ERROR(srcSize_wrong);   /* unauthorized */
    +    if (srcSize != dctx->expected) return ERROR(srcSize_wrong);   /* not allowed */
         if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
     
         switch (dctx->stage)
    @@ -2244,14 +2283,38 @@ size_t ZSTD_resetDStream(ZSTD_DStream* zds)
     size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds,
                                     ZSTD_DStreamParameter_e paramType, unsigned paramValue)
     {
    +    ZSTD_STATIC_ASSERT((unsigned)zdss_loadHeader >= (unsigned)zdss_init);
    +    if ((unsigned)zds->streamStage > (unsigned)zdss_loadHeader)
    +        return ERROR(stage_wrong);
         switch(paramType)
         {
             default : return ERROR(parameter_unsupported);
    -        case DStream_p_maxWindowSize : zds->maxWindowSize = paramValue ? paramValue : (U32)(-1); break;
    +        case DStream_p_maxWindowSize :
    +            DEBUGLOG(4, "setting maxWindowSize = %u KB", paramValue >> 10);
    +            zds->maxWindowSize = paramValue ? paramValue : (U32)(-1);
    +            break;
         }
         return 0;
     }
     
    +size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
    +{
    +    ZSTD_STATIC_ASSERT((unsigned)zdss_loadHeader >= (unsigned)zdss_init);
    +    if ((unsigned)dctx->streamStage > (unsigned)zdss_loadHeader)
    +        return ERROR(stage_wrong);
    +    dctx->maxWindowSize = maxWindowSize;
    +    return 0;
    +}
    +
    +size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)
    +{
    +    ZSTD_STATIC_ASSERT((unsigned)zdss_loadHeader >= (unsigned)zdss_init);
    +    if ((unsigned)dctx->streamStage > (unsigned)zdss_loadHeader)
    +        return ERROR(stage_wrong);
    +    dctx->format = format;
    +    return 0;
    +}
    +
     
     size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds)
     {
    @@ -2276,7 +2339,7 @@ size_t ZSTD_estimateDStreamSize(size_t windowSize)
         return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize;
     }
     
    -ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
    +size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
     {
         U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX;   /* note : should be user-selectable */
         ZSTD_frameHeader zfh;
    @@ -2389,7 +2452,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
                 }
     
                 /* control buffer memory usage */
    -            DEBUGLOG(4, "Control max buffer memory usage");
    +            DEBUGLOG(4, "Control max buffer memory usage (max %u KB)",
    +                        (U32)(zds->maxWindowSize >> 10));
                 zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
                 if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_windowTooLarge);
     
    diff --git a/lib/zstd.h b/lib/zstd.h
    index 047f905b7..5b654d73d 100644
    --- a/lib/zstd.h
    +++ b/lib/zstd.h
    @@ -1247,9 +1247,9 @@ ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
      *  Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to select
      *           how dictionary content will be interpreted and loaded.
      */
    -ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
    -ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
    -ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode);
    +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);   /* not implemented */
    +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);   /* not implemented */
    +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode);   /* not implemented */
     
     
     /*! ZSTD_DCtx_refDDict() :
    @@ -1261,7 +1261,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void
      *  Special : adding a NULL DDict means "return to no-dictionary mode".
      *  Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx.
      */
    -ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
    +ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);   /* not implemented */
     
     
     /*! ZSTD_DCtx_refPrefix() :
    @@ -1273,10 +1273,10 @@ ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
      *  Note 2 : Prefix buffer is referenced. It must outlive compression job.
      *  Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent).
      *           Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode.
    - *  Note 4 : Referencing a raw content prefix costs almost nothing cpu and memory wise.
    + *  Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost.
      */
    -ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize);
    -ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode);
    +ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize);   /* not implemented */
    +ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode);   /* not implemented */
     
     
     /*! ZSTD_DCtx_setMaxWindowSize() :
    @@ -1295,9 +1295,21 @@ ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowS
      *  such ZSTD_f_zstd1_magicless for example.
      * @return : 0, or an error code (which can be tested using ZSTD_isError()).
      */
    -ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
    +ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);   /* implemented, but not functional */
     
     
    +/* How to decompress ?
    + *
    + * currently, use ZSTD_decompressStream().
    + * We could also create a ZSTD_decompress_generic(),
    + * for an API experience similar to the compression one.
    + * It would effectively works exactly the same as ZSTD_decompressStream().
    + *
    + * Also : to re-init a decoding context, use ZSTD_initDStream().
    + * Here also, for a similar API logic, we could create ZSTD_DCtx_reset().
    + * It would behave the same.
    + */
    +
     
     /** ===   Block level API  === **/
     
    diff --git a/programs/Makefile b/programs/Makefile
    index b13629df9..179c1f628 100644
    --- a/programs/Makefile
    +++ b/programs/Makefile
    @@ -40,7 +40,7 @@ CPPFLAGS+= -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/compress \
                -DZSTD_NEWAPI \
                -DXXH_NAMESPACE=ZSTD_   # because xxhash.o already compiled with this macro from library
     CFLAGS  ?= -O3
    -DEBUGFLAGS= -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
    +DEBUGFLAGS+=-Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
                 -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \
                 -Wstrict-prototypes -Wundef -Wpointer-arith -Wformat-security \
                 -Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \
    diff --git a/programs/fileio.c b/programs/fileio.c
    index 623c4f4df..8ce904fc4 100644
    --- a/programs/fileio.c
    +++ b/programs/fileio.c
    @@ -1036,7 +1036,7 @@ static dRess_t FIO_createDResources(const char* dictFileName)
         /* Allocation */
         ress.dctx = ZSTD_createDStream();
         if (ress.dctx==NULL) EXM_THROW(60, "Can't create ZSTD_DStream");
    -    ZSTD_setDStreamParameter(ress.dctx, DStream_p_maxWindowSize, g_memLimit);
    +    CHECK( ZSTD_setDStreamParameter(ress.dctx, DStream_p_maxWindowSize, g_memLimit) );
         ress.srcBufferSize = ZSTD_DStreamInSize();
         ress.srcBuffer = malloc(ress.srcBufferSize);
         ress.dstBufferSize = ZSTD_DStreamOutSize();
    diff --git a/tests/fuzzer.c b/tests/fuzzer.c
    index bfa290c62..92d2f91b2 100644
    --- a/tests/fuzzer.c
    +++ b/tests/fuzzer.c
    @@ -918,6 +918,43 @@ static int basicUnitTests(U32 seed, double compressibility)
             ZSTD_freeCCtx(cctx);
         }
     
    +    /* custom formats tests */
    +    {   ZSTD_CCtx* const cctx = ZSTD_createCCtx();
    +        static const size_t inputSize = CNBuffSize / 2;   /* won't cause pb with small dict size */
    +
    +        /* basic block compression */
    +        DISPLAYLEVEL(4, "test%3i : magic-less format test : ", testNb++);
    +        CHECK( ZSTD_CCtx_setParameter(cctx, ZSTD_p_format, ZSTD_f_zstd1_magicless) );
    +        {   ZSTD_inBuffer in = { CNBuffer, inputSize, 0 };
    +            ZSTD_outBuffer out = { compressedBuffer, ZSTD_compressBound(inputSize), 0 };
    +            size_t const result = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end);
    +            if (result != 0) goto _output_error;
    +            if (in.pos != in.size) goto _output_error;
    +            cSize = out.pos;
    +        }
    +        DISPLAYLEVEL(4, "OK (compress : %u -> %u bytes)\n", (U32)inputSize, (U32)cSize);
    +
    +        DISPLAYLEVEL(4, "test%3i : decompress normally (should fail) : ", testNb++);
    +        {   size_t const decodeResult = ZSTD_decompressDCtx(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize);
    +            if (ZSTD_getErrorCode(decodeResult) != ZSTD_error_prefix_unknown) goto _output_error;
    +            DISPLAYLEVEL(4, "OK : %s \n", ZSTD_getErrorName(decodeResult));
    +        }
    +
    +        DISPLAYLEVEL(4, "test%3i : decompress with magic-less instruction : ", testNb++);
    +        CHECK( ZSTD_initDStream(dctx) );
    +        CHECK( ZSTD_DCtx_setFormat(dctx, ZSTD_f_zstd1_magicless) );
    +        {   ZSTD_inBuffer in = { compressedBuffer, cSize, 0 };
    +            ZSTD_outBuffer out = { decodedBuffer, CNBuffSize, 0 };
    +            size_t const result = ZSTD_decompressStream(dctx, &out, &in);
    +            if (result != 0) goto _output_error;
    +            if (in.pos != in.size) goto _output_error;
    +            if (out.pos != inputSize) goto _output_error;
    +            DISPLAYLEVEL(4, "OK : regenerated %u bytes \n", (U32)out.pos);
    +        }
    +
    +        ZSTD_freeCCtx(cctx);
    +    }
    +
         /* block API tests */
         {   ZSTD_CCtx* const cctx = ZSTD_createCCtx();
             static const size_t dictSize = 65 KB;
    @@ -961,8 +998,8 @@ static int basicUnitTests(U32 seed, double compressibility)
             DISPLAYLEVEL(4, "OK \n");
     
             ZSTD_freeCCtx(cctx);
    -        ZSTD_freeDCtx(dctx);
         }
    +    ZSTD_freeDCtx(dctx);
     
         /* long rle test */
         {   size_t sampleSize = 0;
    diff --git a/tests/playTests.sh b/tests/playTests.sh
    index 38b7a1967..819047e10 100755
    --- a/tests/playTests.sh
    +++ b/tests/playTests.sh
    @@ -45,7 +45,6 @@ then
     fi
     
     isWindows=false
    -ECHO="echo -e"
     INTOVOID="/dev/null"
     case "$OS" in
       Windows*)
    @@ -66,6 +65,11 @@ case "$UNAME" in
       SunOS) DIFF="gdiff" ;;
     esac
     
    +ECHO="echo -e"
    +case "$UNAME" in
    +  Darwin) ECHO="echo" ;;
    +esac
    +
     $ECHO "\nStarting playTests.sh isWindows=$isWindows ZSTD='$ZSTD'"
     
     [ -n "$ZSTD" ] || die "ZSTD variable must be defined!"
    
    From 044fb4c057c5cbfc4472b3da4aca6aed994805a4 Mon Sep 17 00:00:00 2001
    From: Yann Collet 
    Date: Mon, 25 Sep 2017 15:12:09 -0700
    Subject: [PATCH 168/248] implemented magic-less frame decoder
    
    ---
     lib/decompress/zstd_decompress.c | 62 ++++++++++++++++++--------------
     1 file changed, 36 insertions(+), 26 deletions(-)
    
    diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c
    index 47627037b..c4d4654a6 100644
    --- a/lib/decompress/zstd_decompress.c
    +++ b/lib/decompress/zstd_decompress.c
    @@ -152,7 +152,9 @@ size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); }
     
     size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
     {
    -    dctx->expected = ZSTD_frameHeaderSize_prefix;
    +    dctx->expected = (dctx->format==ZSTD_f_zstd1_magicless) ?
    +                            ZSTD_frameHeaderSize_prefix - 4 /* magic size */ :
    +                            ZSTD_frameHeaderSize_prefix;
         dctx->stage = ZSTDds_getFrameHeaderSize;
         dctx->decodedSize = 0;
         dctx->previousDstEnd = NULL;
    @@ -182,6 +184,7 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
         dctx->inBuffSize  = 0;
         dctx->outBuffSize = 0;
         dctx->streamStage = zdss_init;
    +    dctx->format = ZSTD_f_zstd1;
     }
     
     ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
    @@ -488,7 +491,7 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
     *   @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
     static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
     {
    -    size_t const result = ZSTD_getFrameHeader(&(dctx->fParams), src, headerSize);
    +    size_t const result = ZSTD_getFrameHeader_internal(&(dctx->fParams), src, headerSize, dctx->format);
         if (ZSTD_isError(result)) return result;    /* invalid header */
         if (result>0) return ERROR(srcSize_wrong);  /* headerSize too small */
         if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID))
    @@ -1755,33 +1758,31 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
     {
         DEBUGLOG(5, "ZSTD_decompressContinue");
         /* Sanity check */
    -    if (srcSize != dctx->expected) return ERROR(srcSize_wrong);   /* not allowed */
    +    if (srcSize != dctx->expected) return ERROR(srcSize_wrong);  /* not allowed */
         if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
     
         switch (dctx->stage)
         {
         case ZSTDds_getFrameHeaderSize :
    -        if (srcSize != ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong);      /* unauthorized */
             assert(src != NULL);
    -        if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {        /* skippable frame */
    -            memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix);
    -            dctx->expected = ZSTD_skippableHeaderSize - ZSTD_frameHeaderSize_prefix;  /* magic number + skippable frame length */
    -            dctx->stage = ZSTDds_decodeSkippableHeader;
    -            return 0;
    -        }
    -        dctx->headerSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_prefix);
    +        if (dctx->format == ZSTD_f_zstd1) {  /* allows header */
    +            assert(srcSize >= 4);  /* to read skippable magic number */
    +            if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {        /* skippable frame */
    +                memcpy(dctx->headerBuffer, src, srcSize);
    +                dctx->expected = ZSTD_skippableHeaderSize - srcSize;  /* magic number + skippable frame length */
    +                dctx->stage = ZSTDds_decodeSkippableHeader;
    +                return 0;
    +        }   }
    +        dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format);
             if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;
    -        memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix);
    -        if (dctx->headerSize > ZSTD_frameHeaderSize_prefix) {
    -            dctx->expected = dctx->headerSize - ZSTD_frameHeaderSize_prefix;
    -            dctx->stage = ZSTDds_decodeFrameHeader;
    -            return 0;
    -        }
    -        dctx->expected = 0;   /* not necessary to copy more */
    -        /* fall-through */
    +        memcpy(dctx->headerBuffer, src, srcSize);
    +        dctx->expected = dctx->headerSize - srcSize;
    +        dctx->stage = ZSTDds_decodeFrameHeader;
    +        return 0;
    +
         case ZSTDds_decodeFrameHeader:
             assert(src != NULL);
    -        memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected);
    +        memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);
             CHECK_F(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize));
             dctx->expected = ZSTD_blockHeaderSize;
             dctx->stage = ZSTDds_decodeBlockHeader;
    @@ -1813,6 +1814,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
                 }
                 return 0;
             }
    +
         case ZSTDds_decompressLastBlock:
         case ZSTDds_decompressBlock:
             DEBUGLOG(5, "case ZSTDds_decompressBlock");
    @@ -1858,29 +1860,34 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
                 }
                 return rSize;
             }
    +
         case ZSTDds_checkChecksum:
    -        DEBUGLOG(4, "case ZSTDds_checkChecksum");
             assert(srcSize == 4);  /* guaranteed by dctx->expected */
             {   U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
                 U32 const check32 = MEM_readLE32(src);
    -            DEBUGLOG(4, "calculated %08X :: %08X read", h32, check32);
    +            DEBUGLOG(4, "checksum : calculated %08X :: %08X read", h32, check32);
                 if (check32 != h32) return ERROR(checksum_wrong);
                 dctx->expected = 0;
                 dctx->stage = ZSTDds_getFrameHeaderSize;
                 return 0;
             }
    +
         case ZSTDds_decodeSkippableHeader:
    -        {   assert(src != NULL);
    -            memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected);
    -            dctx->expected = MEM_readLE32(dctx->headerBuffer + 4);
    +        {   size_t const skippableFrameHeaderSize = 8;
    +            assert(src != NULL);
    +            assert(srcSize <= skippableFrameHeaderSize);
    +            memcpy(dctx->headerBuffer + (skippableFrameHeaderSize - srcSize), src, srcSize);
    +            dctx->expected = MEM_readLE32(dctx->headerBuffer + 4);   /* note : expect can grow seriously large, beyond buffer size */
                 dctx->stage = ZSTDds_skipFrame;
                 return 0;
             }
    +
         case ZSTDds_skipFrame:
             {   dctx->expected = 0;
                 dctx->stage = ZSTDds_getFrameHeaderSize;
                 return 0;
             }
    +
         default:
             return ERROR(GENERIC);   /* impossible */
         }
    @@ -2308,6 +2315,7 @@ size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
     
     size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)
     {
    +    DEBUGLOG(4, "ZSTD_DCtx_setFormat : %u", (unsigned)format);
         ZSTD_STATIC_ASSERT((unsigned)zdss_loadHeader >= (unsigned)zdss_init);
         if ((unsigned)dctx->streamStage > (unsigned)zdss_loadHeader)
             return ERROR(stage_wrong);
    @@ -2390,7 +2398,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
                 /* fall-through */
     
             case zdss_loadHeader :
    -            {   size_t const hSize = ZSTD_getFrameHeader(&zds->fParams, zds->headerBuffer, zds->lhSize);
    +            DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));
    +            {   size_t const hSize = ZSTD_getFrameHeader_internal(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
    +                DEBUGLOG(5, "header size : %u", (U32)hSize);
                     if (ZSTD_isError(hSize)) {
     #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
                         U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart);
    
    From b8d4a3887fc12f4fcc769d6ce116e716e792139c Mon Sep 17 00:00:00 2001
    From: Yann Collet 
    Date: Mon, 25 Sep 2017 15:25:07 -0700
    Subject: [PATCH 169/248] introduced constant ZSTD_frameIdSize
    
    within zstd_internal.h
    This is the size of magic number.
    
    Avoids using `4` directly in source code, which is a bit less meaningful.
    ---
     lib/common/zstd_internal.h       |  2 ++
     lib/decompress/zstd_decompress.c | 54 +++++++++++++++-----------------
     2 files changed, 28 insertions(+), 28 deletions(-)
    
    diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h
    index 8a24d42f2..694698729 100644
    --- a/lib/common/zstd_internal.h
    +++ b/lib/common/zstd_internal.h
    @@ -105,6 +105,8 @@ static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
     static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 };
     static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 };
     
    +static const size_t ZSTD_frameIdSize = 4;  /* magic number */
    +
     #define ZSTD_BLOCKHEADERSIZE 3   /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
     static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
     typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
    diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c
    index c4d4654a6..d2b85a4a8 100644
    --- a/lib/decompress/zstd_decompress.c
    +++ b/lib/decompress/zstd_decompress.c
    @@ -153,7 +153,7 @@ size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); }
     size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
     {
         dctx->expected = (dctx->format==ZSTD_f_zstd1_magicless) ?
    -                            ZSTD_frameHeaderSize_prefix - 4 /* magic size */ :
    +                            ZSTD_frameHeaderSize_prefix - ZSTD_frameIdSize :
                                 ZSTD_frameHeaderSize_prefix;
         dctx->stage = ZSTDds_getFrameHeaderSize;
         dctx->decodedSize = 0;
    @@ -256,7 +256,7 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
      *  Note 3 : Skippable Frame Identifiers are considered valid. */
     unsigned ZSTD_isFrame(const void* buffer, size_t size)
     {
    -    if (size < 4) return 0;
    +    if (size < ZSTD_frameIdSize) return 0;
         {   U32 const magic = MEM_readLE32(buffer);
             if (magic == ZSTD_MAGICNUMBER) return 1;
             if ((magic & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) return 1;
    @@ -276,8 +276,9 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size)
     static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)
     {
         size_t const minInputSize = (format==ZSTD_f_zstd1_magicless) ?
    -                    ZSTD_frameHeaderSize_prefix - 4 /* magic number size */ :
    +                    ZSTD_frameHeaderSize_prefix - ZSTD_frameIdSize :
                         ZSTD_frameHeaderSize_prefix;
    +    ZSTD_STATIC_ASSERT(ZSTD_frameHeaderSize_prefix >= ZSTD_frameIdSize);
         ZSTD_STATIC_ASSERT((unsigned)ZSTD_f_zstd1 < (unsigned)ZSTD_f_zstd1_magicless);
         assert((unsigned)format <= ZSTD_f_zstd1_magicless);  /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */
         if (srcSize < minInputSize) return ERROR(srcSize_wrong);
    @@ -311,7 +312,7 @@ static size_t ZSTD_getFrameHeader_internal(ZSTD_frameHeader* zfhPtr, const void*
     {
         const BYTE* ip = (const BYTE*)src;
         size_t const minInputSize = (format==ZSTD_f_zstd1_magicless) ?
    -                    ZSTD_frameHeaderSize_prefix - 4 /* magic number size */ :
    +                    ZSTD_frameHeaderSize_prefix - ZSTD_frameIdSize :
                         ZSTD_frameHeaderSize_prefix;
     
         ZSTD_STATIC_ASSERT((unsigned)ZSTD_f_zstd1 < (unsigned)ZSTD_f_zstd1_magicless);
    @@ -325,7 +326,7 @@ static size_t ZSTD_getFrameHeader_internal(ZSTD_frameHeader* zfhPtr, const void*
                 if (srcSize < ZSTD_skippableHeaderSize)
                     return ZSTD_skippableHeaderSize; /* magic number + frame length */
                 memset(zfhPtr, 0, sizeof(*zfhPtr));
    -            zfhPtr->frameContentSize = MEM_readLE32((const char *)src + 4);
    +            zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_frameIdSize);
                 zfhPtr->frameType = ZSTD_skippableFrame;
                 return 0;
             }
    @@ -437,8 +438,8 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
                 size_t skippableSize;
                 if (srcSize < ZSTD_skippableHeaderSize)
                     return ERROR(srcSize_wrong);
    -            skippableSize = MEM_readLE32((const BYTE *)src + 4) +
    -                            ZSTD_skippableHeaderSize;
    +            skippableSize = MEM_readLE32((const BYTE *)src + ZSTD_frameIdSize)
    +                          + ZSTD_skippableHeaderSize;
                 if (srcSize < skippableSize) {
                     return ZSTD_CONTENTSIZE_ERROR;
                 }
    @@ -1484,7 +1485,7 @@ size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
     #endif
         if ( (srcSize >= ZSTD_skippableHeaderSize)
           && (MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START ) {
    -        return ZSTD_skippableHeaderSize + MEM_readLE32((const BYTE*)src + 4);
    +        return ZSTD_skippableHeaderSize + MEM_readLE32((const BYTE*)src + ZSTD_frameIdSize);
         } else {
             const BYTE* ip = (const BYTE*)src;
             const BYTE* const ipstart = ip;
    @@ -1654,8 +1655,8 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
                     size_t skippableSize;
                     if (srcSize < ZSTD_skippableHeaderSize)
                         return ERROR(srcSize_wrong);
    -                skippableSize = MEM_readLE32((const BYTE *)src + 4) +
    -                                ZSTD_skippableHeaderSize;
    +                skippableSize = MEM_readLE32((const BYTE*)src + ZSTD_frameIdSize)
    +                              + ZSTD_skippableHeaderSize;
                     if (srcSize < skippableSize) return ERROR(srcSize_wrong);
     
                     src = (const BYTE *)src + skippableSize;
    @@ -1766,10 +1767,10 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
         case ZSTDds_getFrameHeaderSize :
             assert(src != NULL);
             if (dctx->format == ZSTD_f_zstd1) {  /* allows header */
    -            assert(srcSize >= 4);  /* to read skippable magic number */
    +            assert(srcSize >= ZSTD_frameIdSize);  /* to read skippable magic number */
                 if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {        /* skippable frame */
                     memcpy(dctx->headerBuffer, src, srcSize);
    -                dctx->expected = ZSTD_skippableHeaderSize - srcSize;  /* magic number + skippable frame length */
    +                dctx->expected = ZSTD_skippableHeaderSize - srcSize;  /* remaining to load to get full skippable frame header */
                     dctx->stage = ZSTDds_decodeSkippableHeader;
                     return 0;
             }   }
    @@ -1873,20 +1874,17 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
             }
     
         case ZSTDds_decodeSkippableHeader:
    -        {   size_t const skippableFrameHeaderSize = 8;
    -            assert(src != NULL);
    -            assert(srcSize <= skippableFrameHeaderSize);
    -            memcpy(dctx->headerBuffer + (skippableFrameHeaderSize - srcSize), src, srcSize);
    -            dctx->expected = MEM_readLE32(dctx->headerBuffer + 4);   /* note : expect can grow seriously large, beyond buffer size */
    -            dctx->stage = ZSTDds_skipFrame;
    -            return 0;
    -        }
    +        assert(src != NULL);
    +        assert(srcSize <= ZSTD_skippableHeaderSize);
    +        memcpy(dctx->headerBuffer + (ZSTD_skippableHeaderSize - srcSize), src, srcSize);   /* complete skippable header */
    +        dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_frameIdSize);   /* note : dctx->expected can grow seriously large, beyond local buffer size */
    +        dctx->stage = ZSTDds_skipFrame;
    +        return 0;
     
         case ZSTDds_skipFrame:
    -        {   dctx->expected = 0;
    -            dctx->stage = ZSTDds_getFrameHeaderSize;
    -            return 0;
    -        }
    +        dctx->expected = 0;
    +        dctx->stage = ZSTDds_getFrameHeaderSize;
    +        return 0;
     
         default:
             return ERROR(GENERIC);   /* impossible */
    @@ -1968,7 +1966,7 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict
             if (magic != ZSTD_MAGIC_DICTIONARY) {
                 return ZSTD_refDictContent(dctx, dict, dictSize);   /* pure content mode */
         }   }
    -    dctx->dictID = MEM_readLE32((const char*)dict + 4);
    +    dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_frameIdSize);
     
         /* load entropy tables */
         {   size_t const eSize = ZSTD_loadEntropy(&dctx->entropy, dict, dictSize);
    @@ -2048,7 +2046,7 @@ static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict* ddict)
         {   U32 const magic = MEM_readLE32(ddict->dictContent);
             if (magic != ZSTD_MAGIC_DICTIONARY) return 0;   /* pure content mode */
         }
    -    ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + 4);
    +    ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_frameIdSize);
     
         /* load entropy tables */
         CHECK_E( ZSTD_loadEntropy(&ddict->entropy, ddict->dictContent, ddict->dictSize), dictionary_corrupted );
    @@ -2169,7 +2167,7 @@ unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)
     {
         if (dictSize < 8) return 0;
         if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0;
    -    return MEM_readLE32((const char*)dict + 4);
    +    return MEM_readLE32((const char*)dict + ZSTD_frameIdSize);
     }
     
     /*! ZSTD_getDictID_fromDDict() :
    @@ -2453,7 +2451,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
                 CHECK_F(ZSTD_decompressBegin_usingDDict(zds, zds->ddict));
     
                 if ((MEM_readLE32(zds->headerBuffer) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {  /* skippable frame */
    -                zds->expected = MEM_readLE32(zds->headerBuffer + 4);
    +                zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_frameIdSize);
                     zds->stage = ZSTDds_skipFrame;
                 } else {
                     CHECK_F(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize));
    
    From 6bb781e0f11105c961e89414e81eb8944e8d914b Mon Sep 17 00:00:00 2001
    From: Nick Terrell 
    Date: Mon, 25 Sep 2017 13:29:50 -0700
    Subject: [PATCH 170/248] [fuzz] Add regressiontest targets
    
    ---
     Makefile            | 10 ++++++++++
     tests/fuzz/Makefile | 33 ++++++++++++++++++++++++++++++---
     2 files changed, 40 insertions(+), 3 deletions(-)
    
    diff --git a/Makefile b/Makefile
    index e8bdcea33..7baff751c 100644
    --- a/Makefile
    +++ b/Makefile
    @@ -12,6 +12,7 @@ ZSTDDIR  = lib
     BUILDIR  = build
     ZWRAPDIR = zlibWrapper
     TESTDIR  = tests
    +FUZZDIR  = $(TESTDIR)/fuzz
     
     # Define nul output
     VOID = /dev/null
    @@ -215,6 +216,15 @@ arm-ppc-compilation:
     	$(MAKE) -C $(PRGDIR) clean zstd CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc-static ZSTDRTTEST= MOREFLAGS="-Werror -Wno-attributes -static"
     	$(MAKE) -C $(PRGDIR) clean zstd CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc64-static ZSTDRTTEST= MOREFLAGS="-m64 -static"
     
    +regressiontest:
    +	$(MAKE) -C $(FUZZDIR) regressiontest
    +
    +uasanregressiontest:
    +	$(MAKE) -C $(FUZZDIR) regressiontest CC=clang CXX=clang++ CFLAGS="-O3 -fsanitize=address,undefined" CXXFLAGS="-O3 -fsanitize=address,undefined"
    +
    +msanregressiontest:
    +	$(MAKE) -C $(FUZZDIR) regressiontest CC=clang CXX=clang++ CFLAGS="-O3 -fsanitize=memory" CXXFLAGS="-O3 -fsanitize=memory"
    +
     # run UBsan with -fsanitize-recover=signed-integer-overflow
     # due to a bug in UBsan when doing pointer subtraction
     # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63303
    diff --git a/tests/fuzz/Makefile b/tests/fuzz/Makefile
    index 60822d498..6d2a0cfa9 100644
    --- a/tests/fuzz/Makefile
    +++ b/tests/fuzz/Makefile
    @@ -14,6 +14,13 @@ CPPFLAGS ?=
     LDFLAGS ?=
     ARFLAGS ?=
     LIB_FUZZING_ENGINE ?= libregression.a
    +PYTHON ?= python
    +ifeq ($(shell uname), Darwin)
    +	DOWNLOAD?=curl -L -o
    +else
    +	DOWNLOAD?=wget -O
    +endif
    +CORPORA_URL_PREFIX:=https://github.com/facebook/zstd/releases/download/fuzz-corpora/
     
     ZSTDDIR = ../../lib
     PRGDIR = ../../programs
    @@ -48,18 +55,20 @@ FUZZ_SRC       := \
     FUZZ_OBJ := $(patsubst %.c,%.o, $(wildcard $(FUZZ_SRC)))
     
     
    -.PHONY: default all clean
    +.PHONY: default all clean cleanall
     
     default: all
     
    -all: \
    +FUZZ_TARGETS :=       \
     	simple_round_trip \
     	stream_round_trip \
    -	block_round_trip \
    +	block_round_trip  \
     	simple_decompress \
     	stream_decompress \
     	block_decompress
     
    +all: $(FUZZ_TARGETS)
    +
     %.o: %.c
     	$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $^ -c -o $@
     
    @@ -93,7 +102,25 @@ libFuzzer:
     	@git clone https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer
     	@cd Fuzzer && ./build.sh
     
    +corpora/%_seed_corpus.zip:
    +	@mkdir -p corpora
    +	$(DOWNLOAD) $@ $(CORPORA_URL_PREFIX)$*_seed_corpus.zip
    +
    +corpora/%: corpora/%_seed_corpus.zip
    +	unzip -q $^ -d $@
    +
    +.PHONY: corpora
    +corpora: $(patsubst %,corpora/%,$(FUZZ_TARGETS))
    +
    +regressiontest: corpora
    +	CC="$(CC)" CXX="$(CXX)" CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" LDFLAGS="$(LDFLAGS)" $(PYTHON) ./fuzz.py build all
    +	$(PYTHON) ./fuzz.py regression all
    +
     clean:
     	@$(MAKE) -C $(ZSTDDIR) clean
     	@$(RM) -f *.a *.o
     	@$(RM) -f simple_round_trip stream_round_trip simple_decompress stream_decompress
    +
    +cleanall:
    +	@$(RM) -rf Fuzzer
    +	@$(RM) -rf corpora
    
    From 11e21f23cbac2f0fe2c1bc87d427172211cf8e9f Mon Sep 17 00:00:00 2001
    From: Nick Terrell 
    Date: Mon, 25 Sep 2017 13:32:50 -0700
    Subject: [PATCH 171/248] [fuzz] Mention the corpora in the README
    
    ---
     tests/fuzz/README.md | 8 ++++++++
     1 file changed, 8 insertions(+)
    
    diff --git a/tests/fuzz/README.md b/tests/fuzz/README.md
    index 6d0fab556..f184be646 100644
    --- a/tests/fuzz/README.md
    +++ b/tests/fuzz/README.md
    @@ -1,6 +1,14 @@
     # Fuzzing
     
     Each fuzzing target can be built with multiple engines.
    +Zstd provides a fuzz corpus for each target that can be downloaded with
    +the command:
    +
    +```
    +make corpora
    +```
    +
    +It will download each corpus into `./corpora/TARGET`.
     
     ## fuzz.py
     
    
    From 77d5bc2d626386527a3c290588c86f72fbd5a6f9 Mon Sep 17 00:00:00 2001
    From: Nick Terrell 
    Date: Mon, 25 Sep 2017 13:33:12 -0700
    Subject: [PATCH 172/248] [fuzz][CI] Add regression tests to the CI
    
    ---
     .travis.yml | 2 ++
     circle.yml  | 7 ++++++-
     2 files changed, 8 insertions(+), 1 deletion(-)
    
    diff --git a/.travis.yml b/.travis.yml
    index a52d57af3..67da248d9 100644
    --- a/.travis.yml
    +++ b/.travis.yml
    @@ -21,6 +21,8 @@ matrix:
         - env: Cmd='make arminstall && make aarch64fuzz'
         - env: Cmd='make ppcinstall && make ppcfuzz'
         - env: Cmd='make ppcinstall && make ppc64fuzz'
    +    - env: Cmd='make -j uasanregressiontest'
    +    - env: Cmd='make -j msanregressiontest'
     
     git:
       depth: 1
    diff --git a/circle.yml b/circle.yml
    index e89d548ac..5bc0ce643 100644
    --- a/circle.yml
    +++ b/circle.yml
    @@ -45,7 +45,7 @@ test:
             parallel: true
         - ? |
             if [[ "$CIRCLE_NODE_INDEX" == "0" ]]                                    ; then make ppc64build   && make clean; fi &&
    -        if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make gcc7build    && make clean; fi #could add another test here
    +        if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make gcc7build    && make clean; fi
           :
             parallel: true
         - ? |
    @@ -53,6 +53,11 @@ test:
             if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make -C tests test-legacy test-longmatch test-symbols && make clean; fi
           :
             parallel: true
    +    - ? |
    +        if [[ "$CIRCLE_NODE_INDEX" == "0" ]]                                    ; then make -j regressiontest && make clean; fi &&
    +        if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then true; fi # Could add another test here
    +      :
    +        parallel: true
     
       post:
         - echo Circle CI tests finished
    
    From 917a21325478bf23c5fb8f4605cde4a75f74a986 Mon Sep 17 00:00:00 2001
    From: Nick Terrell 
    Date: Mon, 25 Sep 2017 15:00:50 -0700
    Subject: [PATCH 173/248] [fuzz] Determine flags based on compiler version
    
    ---
     tests/fuzz/fuzz.py | 30 +++++++++++++++++++++++++++++-
     1 file changed, 29 insertions(+), 1 deletion(-)
    
    diff --git a/tests/fuzz/fuzz.py b/tests/fuzz/fuzz.py
    index cd4087090..9864d822d 100755
    --- a/tests/fuzz/fuzz.py
    +++ b/tests/fuzz/fuzz.py
    @@ -140,6 +140,34 @@ def parse_env_flags(args, flags):
         return args
     
     
    +def compiler_version(cc, cxx):
    +    """
    +    Determines the compiler and version.
    +    Only works for clang and gcc.
    +    """
    +    cc_version_bytes = subprocess.check_output([cc, "--version"])
    +    cxx_version_bytes = subprocess.check_output([cxx, "--version"])
    +    if cc_version_bytes.startswith(b'clang'):
    +        assert(cxx_version_bytes.startswith(b'clang'))
    +        compiler = 'clang'
    +    if cc_version_bytes.startswith(b'gcc'):
    +        assert(cxx_version_bytes.startswith(b'g++'))
    +        compiler = 'gcc'
    +    version_regex = b'([0-9])+\.([0-9])+\.([0-9])+'
    +    version_match = re.search(version_regex, cc_version_bytes)
    +    version = tuple(int(version_match.group(i)) for i in range(1, 4))
    +    return compiler, version
    +
    +
    +def overflow_ubsan_flags(cc, cxx):
    +    compiler, version = compiler_version(cc, cxx)
    +    if compiler == 'gcc':
    +        return ['-fno-sanitize=signed-integer-overflow']
    +    if compiler == 'clang' and version >= (5, 0, 0):
    +        return ['-fno-sanitize=pointer-overflow']
    +    return []
    +
    +
     def build_parser(args):
         description = """
         Cleans the repository and builds a fuzz target (or all).
    @@ -364,7 +392,7 @@ def build(args):
         if args.ubsan:
             ubsan_flags = ['-fsanitize=undefined']
             if not args.ubsan_pointer_overflow:
    -            ubsan_flags += ['-fno-sanitize=pointer-overflow']
    +            ubsan_flags += overflow_ubsan_flags(cc, cxx)
             common_flags += ubsan_flags
     
         if args.stateful_fuzzing:
    
    From 6ee05a02b836ee3388d1ade5f671805732797c7c Mon Sep 17 00:00:00 2001
    From: Yann Collet 
    Date: Mon, 25 Sep 2017 15:41:48 -0700
    Subject: [PATCH 174/248] added ZSTD_decompress_generic()
    
    same as ZSTD_decompressStream(),
    just for a similar feeling as the compression side, which uses ZSTD_compress_generic()
    ---
     doc/zstd_manual.html             | 33 +++++++++++++++++++++-----------
     lib/compress/zstd_compress.c     |  1 +
     lib/decompress/zstd_decompress.c |  9 +++++++++
     lib/zstd.h                       | 32 ++++++++++++++++++++-----------
     4 files changed, 53 insertions(+), 22 deletions(-)
    
    diff --git a/doc/zstd_manual.html b/doc/zstd_manual.html
    index 1cb083286..eebc2efb8 100644
    --- a/doc/zstd_manual.html
    +++ b/doc/zstd_manual.html
    @@ -27,8 +27,8 @@
     
  • Buffer-less and synchronous inner streaming functions
  • Buffer-less streaming compression (synchronous mode)
  • Buffer-less streaming decompression (synchronous mode)
  • -
  • === New advanced API (experimental) ===
  • -
  • === Block level API ===
  • +
  • New advanced API (experimental)
  • +
  • Block level API

  • Introduction

    @@ -783,7 +783,7 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
     

    typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
     

    -

    === New advanced API (experimental) ===

    
    +

    New advanced API (experimental)

    
     
     
    typedef enum {
         ZSTD_f_zstd1 = 0,        /* Normal zstd frame format, specified in zstd_compression_format.md (default) */
    @@ -1070,9 +1070,9 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
     


    Advanced parameters for decompression API


    -
    size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
    -size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
    -size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode);
    +
    size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);   /* not implemented */
    +size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);   /* not implemented */
    +size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode);   /* not implemented */
     

    Create an internal DDict from dict buffer, to be used to decompress next frames. @result : 0, or an error code (which can be tested with ZSTD_isError()). @@ -1089,7 +1089,7 @@ size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size


    -
    size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
    +
    size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);   /* not implemented */
     

    Reference a prepared dictionary, to be used to decompress next frames. The dictionary remains active for decompression of future frames using same DCtx. @result : 0, or an error code (which can be tested with ZSTD_isError()). @@ -1100,8 +1100,8 @@ size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size


    -
    size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize);
    -size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode);
    +
    size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize);   /* not implemented */
    +size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode);   /* not implemented */
     

    Reference a prefix (single-usage dictionary) for next compression job. Prefix is **only used once**. It must be explicitly referenced before each frame. If there is a need to use same prefix multiple times, consider embedding it into a ZSTD_DDict instead. @@ -1110,7 +1110,7 @@ size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t Note 2 : Prefix buffer is referenced. It must outlive compression job. Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent). Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode. - Note 4 : Referencing a raw content prefix costs almost nothing cpu and memory wise. + Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost.


    @@ -1131,7 +1131,18 @@ size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t


    -

    === Block level API ===

    
    +
    size_t ZSTD_decompress_generic(ZSTD_DCtx* dctx,
    +                               ZSTD_outBuffer* output,
    +                               ZSTD_inBuffer* input);
    +

    Behave the same as ZSTD_decompressStream. + Decompression parameters cannot be changed once decompression is started. + @return : an error code, which can be tested using ZSTD_isError() + if >0, a hint, nb of expected input bytes for next invocation. + `0` means : a frame has just been fully decoded and flushed. + +


    + +

    Block level API

    
     
     

    Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes). User will have to take in charge required information to regenerate data, such as compressed and content sizes. diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 16137bb74..c9b8b3cb5 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -2574,6 +2574,7 @@ MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, /** ZSTD_compressStream_generic(): * internal function for all *compressStream*() variants and *compress_generic() + * non-static, because can be called from zstdmt.c * @return : hint size for next input */ size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, ZSTD_outBuffer* output, diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index d2b85a4a8..634706a5b 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -2379,7 +2379,10 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB U32 someMoreWork = 1; DEBUGLOG(5, "ZSTD_decompressStream"); + if (input->pos > input->size) return ERROR(GENERIC); /* forbidden */ + if (output->pos > output->size) return ERROR(GENERIC); /* forbidden */ DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos)); + #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) if (zds->legacyVersion) { /* legacy support is incompatible with static dctx */ @@ -2590,3 +2593,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB return nextSrcSizeHint; } } + + +size_t ZSTD_decompress_generic(ZSTD_DCtx* dctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input) +{ + return ZSTD_decompressStream(dctx, output, input); +} diff --git a/lib/zstd.h b/lib/zstd.h index 5b654d73d..cdba0028f 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -908,7 +908,9 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); -/** === New advanced API (experimental) === **/ +/* ============================================ */ +/** New advanced API (experimental) */ +/* ============================================ */ /* notes on API design : * In this proposal, parameters are pushed one by one into an existing context, @@ -1295,23 +1297,31 @@ ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowS * such ZSTD_f_zstd1_magicless for example. * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ -ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); /* implemented, but not functional */ +ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); -/* How to decompress ? - * - * currently, use ZSTD_decompressStream(). - * We could also create a ZSTD_decompress_generic(), - * for an API experience similar to the compression one. - * It would effectively works exactly the same as ZSTD_decompressStream(). - * +/*! ZSTD_decompress_generic() : + * Behave the same as ZSTD_decompressStream. + * Decompression parameters cannot be changed once decompression is started. + * @return : an error code, which can be tested using ZSTD_isError() + * if >0, a hint, nb of expected input bytes for next invocation. + * `0` means : a frame has just been fully decoded and flushed. + */ +ZSTDLIB_API size_t ZSTD_decompress_generic(ZSTD_DCtx* dctx, + ZSTD_outBuffer* output, + ZSTD_inBuffer* input); + + +/* * Also : to re-init a decoding context, use ZSTD_initDStream(). - * Here also, for a similar API logic, we could create ZSTD_DCtx_reset(). + * Here for a similar API logic, we could create ZSTD_DCtx_reset(). * It would behave the same. */ -/** === Block level API === **/ +/* ============================ */ +/** Block level API */ +/* ============================ */ /*! Block functions produce and decode raw zstd blocks, without frame metadata. From f2a913862cd8b4176967967863c05ef2d28e0820 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 25 Sep 2017 15:44:48 -0700 Subject: [PATCH 175/248] added ZSTD_decompress_generic_simpleArgs() --- doc/zstd_manual.html | 12 ++++++++++++ lib/decompress/zstd_decompress.c | 14 ++++++++++++++ lib/zstd.h | 15 ++++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/doc/zstd_manual.html b/doc/zstd_manual.html index eebc2efb8..0847e64a4 100644 --- a/doc/zstd_manual.html +++ b/doc/zstd_manual.html @@ -1142,6 +1142,18 @@ size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t


    +
    size_t ZSTD_decompress_generic_simpleArgs (
    +                ZSTD_DCtx* dctx,
    +                void* dst, size_t dstCapacity, size_t* dstPos,
    +          const void* src, size_t srcSize, size_t* srcPos);
    +

    Same as ZSTD_decompress_generic(), + but using only integral types as arguments. + Argument list is larger than ZSTD_{in,out}Buffer, + but can be helpful for binders from dynamic languages + which have troubles handling structures containing memory pointers. + +


    +

    Block level API

    
     
     

    Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes). diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 634706a5b..78542502a 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -2599,3 +2599,17 @@ size_t ZSTD_decompress_generic(ZSTD_DCtx* dctx, ZSTD_outBuffer* output, ZSTD_inB { return ZSTD_decompressStream(dctx, output, input); } + +size_t ZSTD_decompress_generic_simpleArgs ( + ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos) +{ + ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; + ZSTD_inBuffer input = { src, srcSize, *srcPos }; + /* ZSTD_compress_generic() will check validity of dstPos and srcPos */ + size_t const cErr = ZSTD_decompress_generic(dctx, &output, &input); + *dstPos = output.pos; + *srcPos = input.pos; + return cErr; +} diff --git a/lib/zstd.h b/lib/zstd.h index cdba0028f..494000e74 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -1164,7 +1164,7 @@ ZSTDLIB_API void ZSTD_CCtx_reset(ZSTD_CCtx* cctx); /* Not ready yet ! */ * but can be helpful for binders from dynamic languages * which have troubles handling structures containing memory pointers. */ -size_t ZSTD_compress_generic_simpleArgs ( +ZSTDLIB_API size_t ZSTD_compress_generic_simpleArgs ( ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, size_t* dstPos, const void* src, size_t srcSize, size_t* srcPos, @@ -1312,6 +1312,19 @@ ZSTDLIB_API size_t ZSTD_decompress_generic(ZSTD_DCtx* dctx, ZSTD_inBuffer* input); +/*! ZSTD_decompress_generic_simpleArgs() : + * Same as ZSTD_decompress_generic(), + * but using only integral types as arguments. + * Argument list is larger than ZSTD_{in,out}Buffer, + * but can be helpful for binders from dynamic languages + * which have troubles handling structures containing memory pointers. + */ +ZSTDLIB_API size_t ZSTD_decompress_generic_simpleArgs ( + ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos); + + /* * Also : to re-init a decoding context, use ZSTD_initDStream(). * Here for a similar API logic, we could create ZSTD_DCtx_reset(). From 76cb38d0854433e2dc5ca6a6dd212fccb96ccd41 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Mon, 25 Sep 2017 16:12:46 -0700 Subject: [PATCH 176/248] [zstd] Backport kernel patch from @ColinIanKing * Make the U32 table in `FSE_normalizeCount()` static. * Patch from https://lkml.kernel.org/r/20170922145946.14316-1-colin.king@canonical.com. * Clang makes non-static tables static anyways. gcc however, does [weird things](https://godbolt.org/g/fvTcED). * Benchmarks showed no difference in speed. --- lib/compress/fse_compress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compress/fse_compress.c b/lib/compress/fse_compress.c index 599280b90..549c115d4 100644 --- a/lib/compress/fse_compress.c +++ b/lib/compress/fse_compress.c @@ -582,7 +582,7 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog, if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported size */ if (tableLog < FSE_minTableLog(total, maxSymbolValue)) return ERROR(GENERIC); /* Too small tableLog, compression potentially impossible */ - { U32 const rtbTable[] = { 0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 }; + { static U32 const rtbTable[] = { 0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 }; U64 const scale = 62 - tableLog; U64 const step = ((U64)1<<62) / total; /* <== here, one division ! */ U64 const vStep = 1ULL<<(scale-20); From 52a1d1c6dc2b1ff1f9f732fec391483bf9e190fe Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 25 Sep 2017 16:21:17 -0700 Subject: [PATCH 177/248] added ZSTD_DCtx_reset() --- doc/zstd_manual.html | 11 ++++++++++- lib/decompress/zstd_decompress.c | 11 ++++++++++- lib/zstd.h | 34 +++++++++++++++++++++++--------- tests/fuzzer.c | 4 ++-- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/doc/zstd_manual.html b/doc/zstd_manual.html index 0847e64a4..15b1afea1 100644 --- a/doc/zstd_manual.html +++ b/doc/zstd_manual.html @@ -649,7 +649,7 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict*

    Advanced Streaming decompression functions

    ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
     ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize);    /**< same as ZSTD_initStaticDCtx() */
     typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
    -size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue);
    +size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue);   /* obsolete : this API will be removed in a future version */
     size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: no dictionary will be used if dict == NULL or dictSize < 8 */
     size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict);  /**< note : ddict is referenced, it must outlive decompression session */
     size_t ZSTD_resetDStream(ZSTD_DStream* zds);  /**< re-use decompression parameters from previous init; saves dictionary loading */
    @@ -1154,6 +1154,15 @@ size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t
      
     


    +
    void ZSTD_DCtx_reset(ZSTD_DCtx* dctx);   /* Not ready yet ! */
    +

    Return a DCtx to clean state. + If a decompression was ongoing, any internal data not yet flushed is cancelled. + All parameters are back to default values, including sticky ones. + Dictionary (if any) is dropped. + Parameters can be modified again after a reset. + +


    +

    Block level API

    
     
     

    Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes). diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 78542502a..b9ccc5168 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -2262,13 +2262,15 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di return ZSTD_frameHeaderSize_prefix; } +/* note : this variant can't fail */ size_t ZSTD_initDStream(ZSTD_DStream* zds) { return ZSTD_initDStream_usingDict(zds, NULL, 0); } /* ZSTD_initDStream_usingDDict() : - * ddict will just be referenced, and must outlive decompression session */ + * ddict will just be referenced, and must outlive decompression session + * this function cannot fail */ size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict) { size_t const initResult = ZSTD_initDStream(zds); @@ -2613,3 +2615,10 @@ size_t ZSTD_decompress_generic_simpleArgs ( *srcPos = input.pos; return cErr; } + +void ZSTD_DCtx_reset(ZSTD_DCtx* dctx) +{ + (void)ZSTD_initDStream(dctx); + dctx->format = ZSTD_f_zstd1; + dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; +} diff --git a/lib/zstd.h b/lib/zstd.h index 494000e74..ca60088c8 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -750,7 +750,7 @@ ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledg ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); ZSTDLIB_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */ typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e; -ZSTDLIB_API size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue); +ZSTDLIB_API size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue); /* obsolete : this API will be removed in a future version */ ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: no dictionary will be used if dict == NULL or dictSize < 8 */ ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); /**< note : ddict is referenced, it must outlive decompression session */ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompression parameters from previous init; saves dictionary loading */ @@ -920,7 +920,7 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); * This API is intended to replace all others experimental API. * It can basically do all other use cases, and even new ones. * In constrast with _advanced() variants, it stands a reasonable chance to become "stable", - * after a testing period. + * after a good testing period. */ /* note on naming convention : @@ -930,22 +930,34 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); * It feels clearer in light of potential variants : * ZSTD_CDict_setParameter() (rather than ZSTD_setCDictParameter()) * ZSTD_CCtxParams_setParameter() (rather than ZSTD_setCCtxParamsParameter() ) + * etc... */ /* note on enum design : - * All enum will be manually set to explicit values before reaching "stable API" status */ + * All enum will be pinned to explicit values before reaching "stable API" status */ typedef enum { + /* should we have a ZSTD_f_auto ? + * for the time being, it would mean exactly the same as ZSTD_f_zstd1. + * But, in the future, if several formats are supported, + * on the compression side, it would mean "default format", + * and on the decompression side, it would mean "multi format" + * while ZSTD_f_zstd1 could be reserved to mean "accept only zstd frames". + * Another option could be to define different enums for compression and decompression. + * This question could also be kept for later, but there is also the question of pinning the enum value, + * and pinning the value `0` is especially important */ ZSTD_f_zstd1 = 0, /* Normal zstd frame format, specified in zstd_compression_format.md (default) */ ZSTD_f_zstd1_magicless, /* Variant of zstd frame format, without initial 4-bytes magic number. * Useful to save 4 bytes per generated frame. * Decoder will not be able to recognise this format, requiring instructions. */ - ZSTD_f_zstd1_headerless, /* Variant of zstd frame format, without any frame header; + ZSTD_f_zstd1_headerless, /* Not Implemented Yet ! Complex decoder setting ! Might be removed before release */ + /* Variant of zstd frame format, without any frame header; * Other metadata, like block size or frame checksum, are still generated. * Useful to save between 6 and ZSTD_frameHeaderSize_max bytes per generated frame. * However, required decoding parameters will have to be saved or known by some mechanism. * Decoder will not be able to recognise this format, requiring instructions and parameters. */ - ZSTD_f_zstd1_block /* Generate a zstd compressed block, without any metadata. + ZSTD_f_zstd1_block /* Not Implemented Yet ! Might be removed before release */ + /* Generate a zstd compressed block, without any metadata. * Note that size of block content must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB. * See ZSTD_compressBlock() for more details. * Resulting compressed block can be decoded with ZSTD_decompressBlock(). */ @@ -1325,11 +1337,15 @@ ZSTDLIB_API size_t ZSTD_decompress_generic_simpleArgs ( const void* src, size_t srcSize, size_t* srcPos); -/* - * Also : to re-init a decoding context, use ZSTD_initDStream(). - * Here for a similar API logic, we could create ZSTD_DCtx_reset(). - * It would behave the same. +/*! ZSTD_DCtx_reset() : + * Return a DCtx to clean state. + * If a decompression was ongoing, any internal data not yet flushed is cancelled. + * All parameters are back to default values, including sticky ones. + * Dictionary (if any) is dropped. + * Parameters can be modified again after a reset. */ +ZSTDLIB_API void ZSTD_DCtx_reset(ZSTD_DCtx* dctx); + /* ============================ */ diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 92d2f91b2..a341b5988 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -941,11 +941,11 @@ static int basicUnitTests(U32 seed, double compressibility) } DISPLAYLEVEL(4, "test%3i : decompress with magic-less instruction : ", testNb++); - CHECK( ZSTD_initDStream(dctx) ); + ZSTD_DCtx_reset(dctx); CHECK( ZSTD_DCtx_setFormat(dctx, ZSTD_f_zstd1_magicless) ); { ZSTD_inBuffer in = { compressedBuffer, cSize, 0 }; ZSTD_outBuffer out = { decodedBuffer, CNBuffSize, 0 }; - size_t const result = ZSTD_decompressStream(dctx, &out, &in); + size_t const result = ZSTD_decompress_generic(dctx, &out, &in); if (result != 0) goto _output_error; if (in.pos != in.size) goto _output_error; if (out.pos != inputSize) goto _output_error; From 56f1f0e3ddbd4078a78a11be148ca89dc1cc51fb Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 26 Sep 2017 11:21:36 -0700 Subject: [PATCH 178/248] write summary for --list on multiple files --- programs/fileio.c | 106 +++++++++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 35 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 623c4f4df..db325e441 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -347,13 +347,16 @@ static size_t FIO_createDictBuffer(void** bufferPtr, const char* fileName) fileHandle = fopen(fileName, "rb"); if (fileHandle==0) EXM_THROW(31, "%s: %s", fileName, strerror(errno)); fileSize = UTIL_getFileSize(fileName); - if (fileSize > DICTSIZE_MAX) + if (fileSize > DICTSIZE_MAX) { EXM_THROW(32, "Dictionary file %s is too large (> %u MB)", fileName, DICTSIZE_MAX >> 20); /* avoid extreme cases */ + } *bufferPtr = malloc((size_t)fileSize); if (*bufferPtr==NULL) EXM_THROW(34, "%s", strerror(errno)); - { size_t const readSize = fread(*bufferPtr, 1, (size_t)fileSize, fileHandle); - if (readSize!=fileSize) EXM_THROW(35, "Error reading dictionary file %s", fileName); } + { size_t const readSize = fread(*bufferPtr, 1, (size_t)fileSize, fileHandle); + if (readSize!=fileSize) + EXM_THROW(35, "Error reading dictionary file %s", fileName); + } fclose(fileHandle); return (size_t)fileSize; } @@ -970,7 +973,7 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile char* dstFileName = (char*)malloc(FNSPACE); size_t const suffixSize = suffix ? strlen(suffix) : 0; U64 const srcSize = (nbFiles != 1) ? 0 : UTIL_getFileSize(inFileNamesTable[0]) ; - int const isRegularFile = (nbFiles != 1) ? 0 : UTIL_isRegularFile(inFileNamesTable[0]); + int const isRegularFile = (nbFiles > 1) ? 0 : UTIL_isRegularFile(inFileNamesTable[0]); /* won't write frame content size when nbFiles > 1 */ cRess_t ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, isRegularFile, comprParams); /* init */ @@ -1700,10 +1703,11 @@ int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles typedef struct { int numActualFrames; int numSkippableFrames; - unsigned long long decompressedSize; + U64 decompressedSize; int decompUnavailable; - unsigned long long compressedSize; + U64 compressedSize; int usesCheck; + U32 nbFiles; } fileInfo_t; /** getFileInfo() : @@ -1720,14 +1724,16 @@ static int getFileInfo(fileInfo_t* info, const char* inFileName){ DISPLAY("Error: could not open source file %s\n", inFileName); return 3; } - info->compressedSize = (unsigned long long)UTIL_getFileSize(inFileName); + info->compressedSize = UTIL_getFileSize(inFileName); /* begin analyzing frame */ for ( ; ; ) { BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; size_t const numBytesRead = fread(headerBuffer, 1, sizeof(headerBuffer), srcFile); if (numBytesRead < ZSTD_frameHeaderSize_min) { - if (feof(srcFile) && numBytesRead == 0 && info->compressedSize > 0) { + if ( feof(srcFile) + && (numBytesRead == 0) + && (info->compressedSize > 0) ) { break; } else if (feof(srcFile)) { @@ -1829,6 +1835,7 @@ static int getFileInfo(fileInfo_t* info, const char* inFileName){ } } /* end analyzing frame */ fclose(srcFile); + info->nbFiles = 1; return detectError; } @@ -1841,16 +1848,17 @@ static void displayInfo(const char* inFileName, fileInfo_t* info, int displayLev const char* const checkString = (info->usesCheck ? "XXH64" : "None"); if (displayLevel <= 2) { if (!info->decompUnavailable) { - DISPLAYOUT("Skippable Non-Skippable Compressed Uncompressed Ratio Check Filename\n"); - DISPLAYOUT("%9d %13d %7.2f %2s %9.2f %2s %5.3f %5s %s\n", - info->numSkippableFrames, info->numActualFrames, + DISPLAYOUT("%6d %5d %7.2f %2s %9.2f %2s %5.3f %5s %s\n", + info->numSkippableFrames + info->numActualFrames, + info->numSkippableFrames, compressedSizeUnit, unitStr, decompressedSizeUnit, unitStr, ratio, checkString, inFileName); } else { - DISPLAYOUT("Skippable Non-Skippable Compressed Check Filename\n"); - DISPLAYOUT("%9d %13d %7.2f MB %5s %s\n", - info->numSkippableFrames, info->numActualFrames, - compressedSizeUnit, checkString, inFileName); + DISPLAYOUT("%6d %5d %7.2f %2s %5s %s\n", + info->numSkippableFrames + info->numActualFrames, + info->numSkippableFrames, + compressedSizeUnit, unitStr, + checkString, inFileName); } } else { DISPLAYOUT("# Zstandard Frames: %d\n", info->numActualFrames); @@ -1867,33 +1875,40 @@ static void displayInfo(const char* inFileName, fileInfo_t* info, int displayLev } } +static fileInfo_t FIO_addFInfo(fileInfo_t fi1, fileInfo_t fi2) +{ + fileInfo_t total; + total.numActualFrames = fi1.numActualFrames + fi2.numActualFrames; + total.numSkippableFrames = fi1.numSkippableFrames + fi2.numSkippableFrames; + total.compressedSize = fi1.compressedSize + fi2.compressedSize; + total.decompressedSize = fi1.decompressedSize + fi2.decompressedSize; + total.decompUnavailable = fi1.decompUnavailable | fi2.decompUnavailable; + total.usesCheck = fi1.usesCheck & fi2.usesCheck; + total.nbFiles = fi1.nbFiles + fi2.nbFiles; + return total; +} -static int FIO_listFile(const char* inFileName, int displayLevel, unsigned fileNo, unsigned numFiles){ +static int FIO_listFile(fileInfo_t* total, const char* inFileName, int displayLevel){ /* initialize info to avoid warnings */ fileInfo_t info; memset(&info, 0, sizeof(info)); - DISPLAYOUT("%s (%u/%u):\n", inFileName, fileNo, numFiles); - { - int const error = getFileInfo(&info, inFileName); + { int const error = getFileInfo(&info, inFileName); if (error == 1) { /* display error, but provide output */ - DISPLAY("An error occurred with getting file info\n"); + DISPLAY("An error occurred while getting file info \n"); } else if (error == 2) { - DISPLAYOUT("File %s not compressed with zstd\n", inFileName); - if (displayLevel > 2) { - DISPLAYOUT("\n"); - } + DISPLAYOUT("File %s not compressed by zstd \n", inFileName); + if (displayLevel > 2) DISPLAYOUT("\n"); return 1; } else if (error == 3) { - /* error occurred with opening the file */ - if (displayLevel > 2) { - DISPLAYOUT("\n"); - } + /* error occurred while opening the file */ + if (displayLevel > 2) DISPLAYOUT("\n"); return 1; } displayInfo(inFileName, &info, displayLevel); + *total = FIO_addFInfo(*total, info); return error; } } @@ -1903,15 +1918,36 @@ int FIO_listMultipleFiles(unsigned numFiles, const char** filenameTable, int dis DISPLAYOUT("No files given\n"); return 0; } - DISPLAYOUT("===========================================\n"); - DISPLAYOUT("Printing information about compressed files\n"); - DISPLAYOUT("===========================================\n"); - DISPLAYOUT("Number of files listed: %u\n", numFiles); - { - int error = 0; + DISPLAYOUT("Frames Skips Compressed Uncompressed Ratio Check Filename\n"); + { int error = 0; unsigned u; + fileInfo_t total; + memset(&total, 0, sizeof(total)); + total.usesCheck = 1; for (u=0; u 1) { + unsigned const unit = total.compressedSize < (1 MB) ? (1 KB) : (1 MB); + const char* const unitStr = total.compressedSize < (1 MB) ? "KB" : "MB"; + double const compressedSizeUnit = (double)total.compressedSize / unit; + double const decompressedSizeUnit = (double)total.decompressedSize / unit; + double const ratio = (total.compressedSize == 0) ? 0 : ((double)total.decompressedSize)/total.compressedSize; + const char* const checkString = (total.usesCheck ? "XXH64" : ""); + DISPLAYOUT("----------------------------------------------------------------- \n"); + if (total.decompUnavailable) { + DISPLAYOUT("%6d %5d %7.2f %2s %5s %u files\n", + total.numSkippableFrames + total.numActualFrames, + total.numSkippableFrames, + compressedSizeUnit, unitStr, + checkString, total.nbFiles); + } else { + DISPLAYOUT("%6d %5d %7.2f %2s %9.2f %2s %5.3f %5s %u files\n", + total.numSkippableFrames + total.numActualFrames, + total.numSkippableFrames, + compressedSizeUnit, unitStr, decompressedSizeUnit, unitStr, + ratio, checkString, total.nbFiles); + } } return error; } From 3095ca8c56864552d910564cfd4f0b18f56f9b81 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 26 Sep 2017 13:53:50 -0700 Subject: [PATCH 179/248] fixed minor conversion warnings for g++ on Linux U64 is not considered equivalent to unsigned long long --- programs/fileio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index db325e441..3ca35e1af 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1864,10 +1864,12 @@ static void displayInfo(const char* inFileName, fileInfo_t* info, int displayLev DISPLAYOUT("# Zstandard Frames: %d\n", info->numActualFrames); DISPLAYOUT("# Skippable Frames: %d\n", info->numSkippableFrames); DISPLAYOUT("Compressed Size: %.2f %2s (%llu B)\n", - compressedSizeUnit, unitStr, info->compressedSize); + compressedSizeUnit, unitStr, + (unsigned long long)info->compressedSize); if (!info->decompUnavailable) { DISPLAYOUT("Decompressed Size: %.2f %2s (%llu B)\n", - decompressedSizeUnit, unitStr, info->decompressedSize); + decompressedSizeUnit, unitStr, + (unsigned long long)info->decompressedSize); DISPLAYOUT("Ratio: %.4f\n", ratio); } DISPLAYOUT("Check: %s\n", checkString); From c233bdbaeef497a946256aeb6aff9fc108d4d2d7 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 22 Sep 2017 14:04:39 -0700 Subject: [PATCH 180/248] Increase maximum window size * Maximum window size in 32-bit mode is 1GB, since allocations for 2GB fail on my Mac. * Maximum window size in 64-bit mode is 2GB, since that is the largest power of 2 that works with the overflow prevention. * Allow `--long=windowLog` to set the window log, along with `--zstd=wlog=#`. These options also set the window size during decompression, but don't override `--memory=#` if it is set. * Present a helpful error message when the window size is too large during decompression. * The long range matcher defaults to a hash log 7 less than the window log, which keeps it at 20 for window log 27. * Keep the default long range matcher window size and the default maximum window size at 27 for the API and CLI. * Add tests that use the maximum window size and hash size for compression and decompression. --- lib/common/zstd_internal.h | 1 + lib/compress/zstd_compress.c | 14 ++++++------- lib/compress/zstd_ldm.c | 8 +++++-- lib/compress/zstd_ldm.h | 2 +- lib/decompress/zstd_decompress.c | 6 +++--- lib/zstd.h | 10 +++++---- programs/fileio.c | 35 +++++++++++++++++++++++++++++-- programs/zstd.1 | 18 ++++++++++++---- programs/zstd.1.md | 20 ++++++++++++------ programs/zstdcli.c | 27 ++++++++++++++++++++++-- tests/playTests.sh | 36 ++++++++++++++++++++++++-------- tests/zstreamtest.c | 2 ++ 12 files changed, 139 insertions(+), 40 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 403c0cbdb..1defee671 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -102,6 +102,7 @@ static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; #define BIT0 1 #define ZSTD_WINDOWLOG_ABSOLUTEMIN 10 +#define ZSTD_WINDOWLOG_DEFAULTMAX 27 /* Default maximum allowed window log */ static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 782439f77..e84149bd3 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -429,7 +429,7 @@ size_t ZSTD_CCtxParam_setParameter( case ZSTD_p_enableLongDistanceMatching : if (value != 0) { ZSTD_cLevelToCCtxParams(params); - params->cParams.windowLog = ZSTD_LDM_WINDOW_LOG; + params->cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; } return ZSTD_ldm_initializeParameters(¶ms->ldmParams, value); @@ -1599,7 +1599,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, const BYTE* ip = (const BYTE*)src; BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; - U32 const maxDist = 1 << cctx->appliedParams.cParams.windowLog; + U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog; if (cctx->appliedParams.fParams.checksumFlag && srcSize) XXH64_update(&cctx->xxhState, src, srcSize); @@ -1630,9 +1630,9 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, * windowLog <= 31 ==> 3<<29 + 1<lowLimit > (3U<<29)) { - U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy)) - 1; + U32 const cycleMask = ((U32)1 << ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy)) - 1; U32 const current = (U32)(ip - cctx->base); - U32 const newCurrent = (current & cycleMask) + (1 << cctx->appliedParams.cParams.windowLog); + U32 const newCurrent = (current & cycleMask) + ((U32)1 << cctx->appliedParams.cParams.windowLog); U32 const correction = current - newCurrent; ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); @@ -1688,7 +1688,7 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */ U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */ U32 const checksumFlag = params.fParams.checksumFlag>0; - U32 const windowSize = 1U << params.cParams.windowLog; + U32 const windowSize = (U32)1 << params.cParams.windowLog; U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize); BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3); U32 const fcsCode = params.fParams.contentSizeFlag ? @@ -1788,7 +1788,7 @@ size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) { ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams(cctx->appliedParams, 0, 0); - return MIN (ZSTD_BLOCKSIZE_MAX, 1 << cParams.windowLog); + return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog); } size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) @@ -1837,7 +1837,7 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t case ZSTD_btopt: case ZSTD_btultra: if (srcSize >= HASH_READ_SIZE) - ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->appliedParams.cParams.searchLog, zc->appliedParams.cParams.searchLength); + ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, (U32)1 << zc->appliedParams.cParams.searchLog, zc->appliedParams.cParams.searchLength); break; default: diff --git a/lib/compress/zstd_ldm.c b/lib/compress/zstd_ldm.c index e40007c19..be50872cf 100644 --- a/lib/compress/zstd_ldm.c +++ b/lib/compress/zstd_ldm.c @@ -14,14 +14,14 @@ #define LDM_BUCKET_SIZE_LOG 3 #define LDM_MIN_MATCH_LENGTH 64 -#define LDM_HASH_LOG 20 +#define LDM_HASH_RLOG 7 #define LDM_HASH_CHAR_OFFSET 10 size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm) { ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX); params->enableLdm = enableLdm>0; - params->hashLog = LDM_HASH_LOG; + params->hashLog = 0; params->bucketSizeLog = LDM_BUCKET_SIZE_LOG; params->minMatchLength = LDM_MIN_MATCH_LENGTH; params->hashEveryLog = ZSTD_LDM_HASHEVERYLOG_NOTSET; @@ -30,6 +30,10 @@ size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm) void ZSTD_ldm_adjustParameters(ldmParams_t* params, U32 windowLog) { + if (params->hashLog == 0) { + params->hashLog = MAX(ZSTD_HASHLOG_MIN, windowLog - LDM_HASH_RLOG); + assert(params->hashLog <= ZSTD_HASHLOG_MAX); + } if (params->hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET) { params->hashEveryLog = windowLog < params->hashLog ? 0 : windowLog - params->hashLog; diff --git a/lib/compress/zstd_ldm.h b/lib/compress/zstd_ldm.h index 7a6248399..d6d3d42c3 100644 --- a/lib/compress/zstd_ldm.h +++ b/lib/compress/zstd_ldm.h @@ -20,7 +20,7 @@ extern "C" { * Long distance matching ***************************************/ -#define ZSTD_LDM_WINDOW_LOG 27 +#define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_DEFAULTMAX #define ZSTD_LDM_HASHEVERYLOG_NOTSET 9999 /** ZSTD_compressBlock_ldm_generic() : diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index c91e082ed..ebfa93c37 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -35,7 +35,7 @@ * Frames requiring more memory will be rejected. */ #ifndef ZSTD_MAXWINDOWSIZE_DEFAULT -# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U64)1 << ZSTD_WINDOWLOG_MAX) + 1) /* defined within zstd.h */ +# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_DEFAULTMAX) + 1) #endif @@ -913,7 +913,7 @@ static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e l offset = 0; else { ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); - ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 2); + ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); assert(ofBits <= MaxOff); if (MEM_32bits() && longOffsets) { U32 const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN_32-1); @@ -1159,7 +1159,7 @@ seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const long offset = 0; else { ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); - ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 2); + ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); assert(ofBits <= MaxOff); if (MEM_32bits() && longOffsets) { U32 const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN_32-1); diff --git a/lib/zstd.h b/lib/zstd.h index a6266dfd8..b7c75d5f2 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -376,8 +376,8 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output #define ZSTD_MAGIC_SKIPPABLE_START 0x184D2A50U #define ZSTD_MAGIC_DICTIONARY 0xEC30A437 /* v0.7+ */ -#define ZSTD_WINDOWLOG_MAX_32 27 -#define ZSTD_WINDOWLOG_MAX_64 27 +#define ZSTD_WINDOWLOG_MAX_32 30 +#define ZSTD_WINDOWLOG_MAX_64 31 #define ZSTD_WINDOWLOG_MAX ((unsigned)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64)) #define ZSTD_WINDOWLOG_MIN 10 #define ZSTD_HASHLOG_MAX MIN(ZSTD_WINDOWLOG_MAX, 30) @@ -941,7 +941,9 @@ typedef enum { * Special: value 0 means "do not change cLevel". */ ZSTD_p_windowLog, /* Maximum allowed back-reference distance, expressed as power of 2. * Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX. - * Special: value 0 means "do not change windowLog". */ + * Special: value 0 means "do not change windowLog". + * Note: Using a window size greater than ZSTD_MAXWINDOWSIZE_DEFAULT (default: 2^27) + * requires setting the maximum window size at least as large during decompression. */ ZSTD_p_hashLog, /* Size of the probe table, as a power of 2. * Resulting table size is (1 << (hashLog+2)). * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX. @@ -1009,7 +1011,7 @@ typedef enum { * Larger values increase memory usage and compression ratio, but decrease * compression speed. * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX - * (default: 20). */ + * (default: windowlog - 7). */ ZSTD_p_ldmMinMatch, /* Minimum size of searched matches for long distance matcher. * Larger/too small values usually decrease compression ratio. * Must be clamped between ZSTD_LDM_MINMATCH_MIN diff --git a/programs/fileio.c b/programs/fileio.c index 623c4f4df..a4b50fc23 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -37,6 +37,7 @@ # include #endif +#include "bitstream.h" #include "mem.h" #include "fileio.h" #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_magicNumber, ZSTD_frameHeaderSize_max */ @@ -1167,6 +1168,35 @@ static unsigned FIO_passThrough(FILE* foutput, FILE* finput, void* buffer, size_ return 0; } +static void FIO_zstdErrorHelp(dRess_t* ress, size_t ret, char const* srcFileName) +{ + ZSTD_frameHeader header; + /* No special help for these errors */ + if (ZSTD_getErrorCode(ret) != ZSTD_error_frameParameter_windowTooLarge) + return; + /* Try to decode the frame header */ + ret = ZSTD_getFrameHeader(&header, ress->srcBuffer, ress->srcBufferLoaded); + if (ret == 0) { + U32 const windowSize = (U32)header.windowSize; + U32 const windowLog = BIT_highbit32(windowSize) + ((windowSize & (windowSize - 1)) != 0); + U32 const windowMB = (windowSize >> 20) + (windowSize & ((1 MB) - 1)); + assert(header.windowSize <= (U64)((U32)-1)); + assert(g_memLimit > 0); + DISPLAYLEVEL(1, "%s : Window size larger than maximum : %llu > %u\n", + srcFileName, header.windowSize, g_memLimit); + if (windowLog <= ZSTD_WINDOWLOG_MAX) { + DISPLAYLEVEL(1, "%s : Use --long=%u or --memory=%uMB\n", + srcFileName, windowLog, windowMB); + return; + } + } else if (ZSTD_getErrorCode(ret) != ZSTD_error_frameParameter_windowTooLarge) { + DISPLAYLEVEL(1, "%s : Error decoding frame header to read window size : %s\n", + srcFileName, ZSTD_getErrorName(ret)); + return; + } + DISPLAYLEVEL(1, "%s : Window log larger than ZSTD_WINDOWLOG_MAX=%u not supported\n", + srcFileName, ZSTD_WINDOWLOG_MAX); +} /** FIO_decompressFrame() : * @return : size of decoded zstd frame, or an error code @@ -1183,8 +1213,8 @@ unsigned long long FIO_decompressZstdFrame(dRess_t* ress, ZSTD_resetDStream(ress->dctx); if (strlen(srcFileName)>20) srcFileName += strlen(srcFileName)-20; /* display last 20 characters */ - /* Header loading (optional, saves one loop) */ - { size_t const toRead = 9; + /* Header loading : ensures ZSTD_getFrameHeader() will succeed */ + { size_t const toRead = ZSTD_FRAMEHEADERSIZE_MAX; if (ress->srcBufferLoaded < toRead) ress->srcBufferLoaded += fread(((char*)ress->srcBuffer) + ress->srcBufferLoaded, 1, toRead - ress->srcBufferLoaded, finput); } @@ -1197,6 +1227,7 @@ unsigned long long FIO_decompressZstdFrame(dRess_t* ress, if (ZSTD_isError(readSizeHint)) { DISPLAYLEVEL(1, "%s : Decoding error (36) : %s \n", srcFileName, ZSTD_getErrorName(readSizeHint)); + FIO_zstdErrorHelp(ress, readSizeHint, srcFileName); return FIO_ERROR_FRAME_DECODING; } diff --git a/programs/zstd.1 b/programs/zstd.1 index 0fad1d277..b68899b2d 100644 --- a/programs/zstd.1 +++ b/programs/zstd.1 @@ -104,8 +104,11 @@ Display information related to a zstd compressed file, such as size, ratio, and unlocks high compression levels 20+ (maximum 22), using a lot more memory\. Note that decompression will also require more memory when using these levels\. . .TP -\fB\-\-long\fR -enables long distance matching\. This increases the window size (\fBwindowLog\fR) and memory usage for both the compressor and decompressor\. This setting is designed to improve the compression ratio for files with long matches at a large distance (up to the maximum window size, 128 MiB)\. +\fB\-\-long[=#]\fR +enables long distance matching with \fB#\fR \fBwindowLog\fR, if not \fB#\fR is not present it defaults to \fB27\fR\. This increases the window size (\fBwindowLog\fR) and memory usage for both the compressor and decompressor\. This setting is designed to improve the compression ratio for files with long matches at a large distance\. +. +.IP +Note: If \fBwindowLog\fR is set to larger than 27, \fB\-\-long=windowLog\fR or \fB\-\-memory=windowSize\fR needs to be passed to the decompressor\. . .TP \fB\-T#\fR, \fB\-\-threads=#\fR @@ -190,6 +193,10 @@ Dictionary saved into \fBfile\fR (default name: dictionary)\. Limit dictionary to specified size (default: 112640)\. . .TP +\fB\-B#\fR +Split input files in blocks of size # (default: no split) +. +.TP \fB\-\-dictID=#\fR A dictionary ID is a locally unique ID that a decoder can use to verify it is using the right dictionary\. By default, zstd will create a 4\-bytes random number ID\. It\'s possible to give a precise number instead\. Short numbers have an advantage : an ID < 256 will only need 1 byte in the compressed frame header, and an ID < 65536 will only need 2 bytes\. This compares favorably to 4 bytes default\. However, it\'s up to the dictionary manager to not assign twice the same ID to 2 different dictionaries\. . @@ -267,7 +274,10 @@ There are 8 strategies numbered from 1 to 8, from faster to stronger: 1=ZSTD_fas Specify the maximum number of bits for a match distance\. . .IP -The higher number of increases the chance to find a match which usually improves compression ratio\. It also increases memory requirements for the compressor and decompressor\. The minimum \fIwlog\fR is 10 (1 KiB) and the maximum is 27 (128 MiB)\. +The higher number of increases the chance to find a match which usually improves compression ratio\. It also increases memory requirements for the compressor and decompressor\. The minimum \fIwlog\fR is 10 (1 KiB) and the maximum is 30 (1 GiB) on 32\-bit platforms and 31 (2 GiB) on 64\-bit platforms\. +. +.IP +Note: If \fBwindowLog\fR is set to larger than 27, \fB\-\-long=windowLog\fR or \fB\-\-memory=windowSize\fR needs to be passed to the decompressor\. . .TP \fBhashLog\fR=\fIhlog\fR, \fBhlog\fR=\fIhlog\fR @@ -340,7 +350,7 @@ Bigger hash tables usually improve compression ratio at the expense of more memo The minimum \fIldmhlog\fR is 6 and the maximum is 26 (default: 20)\. . .TP -\fBldmSearchLength\fR=\fIldmslen\fR, \fBldmSlen\fR=\fIldmslen\fR +\fBldmSearchLength\fR=\fIldmslen\fR, \fBldmslen\fR=\fIldmslen\fR Specify the minimum searched length of a match for long distance matching\. . .IP diff --git a/programs/zstd.1.md b/programs/zstd.1.md index e446422b6..562f8721e 100644 --- a/programs/zstd.1.md +++ b/programs/zstd.1.md @@ -105,12 +105,16 @@ the last one takes effect. * `--ultra`: unlocks high compression levels 20+ (maximum 22), using a lot more memory. Note that decompression will also require more memory when using these levels. -* `--long`: - enables long distance matching. +* `--long[=#]`: + enables long distance matching with `#` `windowLog`, if not `#` is not + present it defaults to `27`. This increases the window size (`windowLog`) and memory usage for both the - compressor and decompressor. This setting is designed to improve the - compression ratio for files with long matches at a large distance - (up to the maximum window size, 128 MiB). + compressor and decompressor. + This setting is designed to improve the compression ratio for files with + long matches at a large distance. + + Note: If `windowLog` is set to larger than 27, `--long=windowLog` or + `--memory=windowSize` needs to be passed to the decompressor. * `-T#`, `--threads=#`: Compress using `#` threads (default: 1). If `#` is 0, attempt to detect and use the number of physical CPU cores. @@ -275,7 +279,11 @@ The list of available _options_: The higher number of increases the chance to find a match which usually improves compression ratio. It also increases memory requirements for the compressor and decompressor. - The minimum _wlog_ is 10 (1 KiB) and the maximum is 27 (128 MiB). + The minimum _wlog_ is 10 (1 KiB) and the maximum is 30 (1 GiB) on 32-bit + platforms and 31 (2 GiB) on 64-bit platforms. + + Note: If `windowLog` is set to larger than 27, `--long=windowLog` or + `--memory=windowSize` needs to be passed to the decompressor. - `hashLog`=_hlog_, `hlog`=_hlog_: Specify the maximum number of bits for a hash table. diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 89e97c294..3478028ca 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -72,6 +72,7 @@ static const char* g_defaultDictName = "dictionary"; static const unsigned g_defaultMaxDictSize = 110 KB; static const int g_defaultDictCLevel = 3; static const unsigned g_defaultSelectivityLevel = 9; +static const unsigned g_defaultMaxWindowLog = 27; #define OVERLAP_LOG_DEFAULT 9999 #define LDM_PARAM_DEFAULT 9999 /* Default for parameters where 0 is valid */ static U32 g_overlapLog = OVERLAP_LOG_DEFAULT; @@ -129,7 +130,7 @@ static int usage_advanced(const char* programName) DISPLAY( " -l : print information about zstd compressed files \n"); #ifndef ZSTD_NOCOMPRESS DISPLAY( "--ultra : enable levels beyond %i, up to %i (requires more memory)\n", ZSTDCLI_CLEVEL_MAX, ZSTD_maxCLevel()); - DISPLAY( "--long : enable long distance matching (requires more memory)\n"); + DISPLAY( "--long[=#] : enable long distance matching with given window log (default : %u)\n", g_defaultMaxWindowLog); #ifdef ZSTD_MULTITHREAD DISPLAY( " -T# : use # threads for compression (default:1) \n"); DISPLAY( " -B# : select size of each job (default:0==automatic) \n"); @@ -459,7 +460,6 @@ int main(int argCount, const char* argv[]) if (!strcmp(argument, "--quiet")) { g_displayLevel--; continue; } if (!strcmp(argument, "--stdout")) { forceStdout=1; outFileName=stdoutmark; g_displayLevel-=(g_displayLevel==2); continue; } if (!strcmp(argument, "--ultra")) { ultra=1; continue; } - if (!strcmp(argument, "--long")) { ldmFlag = 1; continue; } if (!strcmp(argument, "--check")) { FIO_setChecksumFlag(2); continue; } if (!strcmp(argument, "--no-check")) { FIO_setChecksumFlag(0); continue; } if (!strcmp(argument, "--sparse")) { FIO_setSparseWrite(2); continue; } @@ -514,6 +514,22 @@ int main(int argCount, const char* argv[]) if (longCommandWArg(&argument, "--maxdict=")) { maxDictSize = readU32FromChar(&argument); continue; } if (longCommandWArg(&argument, "--dictID=")) { dictID = readU32FromChar(&argument); continue; } if (longCommandWArg(&argument, "--zstd=")) { if (!parseCompressionParameters(argument, &compressionParams)) CLEAN_RETURN(badusage(programName)); continue; } + if (longCommandWArg(&argument, "--long")) { + unsigned ldmWindowLog = 0; + ldmFlag = 1; + /* Parse optional window log */ + if (*argument == '=') { + ++argument; + ldmWindowLog = readU32FromChar(&argument); + } else if (*argument != 0) { + /* Invalid character following --long */ + CLEAN_RETURN(badusage(programName)); + } + /* Only set windowLog if not already set by --zstd */ + if (compressionParams.windowLog == 0) + compressionParams.windowLog = ldmWindowLog; + continue; + } /* fall-through, will trigger bad_usage() later on */ } @@ -830,6 +846,13 @@ int main(int argCount, const char* argv[]) #endif } else { /* decompression or test */ #ifndef ZSTD_NODECOMPRESS + if (memLimit == 0) { + if (compressionParams.windowLog == 0) + memLimit = (U32)1 << g_defaultMaxWindowLog; + else { + memLimit = (U32)1 << (compressionParams.windowLog & 31); + } + } FIO_setMemLimit(memLimit); if (filenameIdx==1 && outFileName) operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName); diff --git a/tests/playTests.sh b/tests/playTests.sh index 38b7a1967..b3e0b8ab8 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -13,11 +13,16 @@ roundTripTest() { cLevel="$2" proba="" fi + if [ -n "$4" ]; then + dLevel="$4" + else + dLevel="$cLevel" + fi rm -f tmp1 tmp2 - $ECHO "roundTripTest: ./datagen $1 $proba | $ZSTD -v$cLevel | $ZSTD -d" + $ECHO "roundTripTest: ./datagen $1 $proba | $ZSTD -v$cLevel | $ZSTD -d$dLevel" ./datagen $1 $proba | $MD5SUM > tmp1 - ./datagen $1 $proba | $ZSTD --ultra -v$cLevel | $ZSTD -d | $MD5SUM > tmp2 + ./datagen $1 $proba | $ZSTD --ultra -v$cLevel | $ZSTD -d$dLevel | $MD5SUM > tmp2 $DIFF -q tmp1 tmp2 } @@ -29,12 +34,17 @@ fileRoundTripTest() { local_c="$2" local_p="" fi + if [ -n "$4" ]; then + local_d="$4" + else + local_d="$local_c" + fi rm -f tmp.zstd tmp.md5.1 tmp.md5.2 - $ECHO "fileRoundTripTest: ./datagen $1 $local_p > tmp && $ZSTD -v$local_c -c tmp | $ZSTD -d" + $ECHO "fileRoundTripTest: ./datagen $1 $local_p > tmp && $ZSTD -v$local_c -c tmp | $ZSTD -d$local_d" ./datagen $1 $local_p > tmp cat tmp | $MD5SUM > tmp.md5.1 - $ZSTD --ultra -v$local_c -c tmp | $ZSTD -d | $MD5SUM > tmp.md5.2 + $ZSTD --ultra -v$local_c -c tmp | $ZSTD -d$local_d | $MD5SUM > tmp.md5.2 $DIFF -q tmp.md5.1 tmp.md5.2 } @@ -669,16 +679,24 @@ roundTripTest -g140000000 -P60 "5 --long" roundTripTest -g70000000 -P70 "8 --long" roundTripTest -g18000001 -P80 "18 --long" fileRoundTripTest -g4100M -P99 "1 --long" +# Test large window logs +roundTripTest -g4100M -P50 "1 --long=30" +roundTripTest -g4100M -P50 "1 --long --zstd=wlog=30,clog=30" +# Test parameter parsing +roundTripTest -g1M -P50 "1 --long=30" " --memory=1024MB" +roundTripTest -g1M -P50 "1 --long=30 --zstd=wlog=29" " --memory=512MB" +roundTripTest -g1M -P50 "1 --long=30" " --long=29 --memory=1024MB" +roundTripTest -g1M -P50 "1 --long=30" " --zstd=wlog=29 --memory=1024MB" if [ -n "$hasMT" ] then $ECHO "\n**** zstdmt long round-trip tests **** " - roundTripTest -g99000000 -P99 "20 -T2" - roundTripTest -g6000000000 -P99 "1 -T2" - roundTripTest -g1500000000 -P97 "1 -T999" - fileRoundTripTest -g4195M -P98 " -T0" - roundTripTest -g1500000000 -P97 "1 --long -T999" + roundTripTest -g99000000 -P99 "20 -T2" " " + roundTripTest -g6000000000 -P99 "1 -T2" " " + roundTripTest -g1500000000 -P97 "1 -T999" " " + fileRoundTripTest -g4195M -P98 " -T0" " " + roundTripTest -g1500000000 -P97 "1 --long=23 -T2" " " else $ECHO "\n**** no multithreading, skipping zstdmt tests **** " fi diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index e52335da0..3f190f050 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -50,6 +50,7 @@ static const U32 g_cLevelMax_smallTests = 10; #define COMPRESSIBLE_NOISE_LENGTH (10 MB) #define FUZ_COMPRESSIBILITY_DEFAULT 50 static const U32 prime32 = 2654435761U; +static const U32 windowLogMax = 27; /*-************************************ @@ -1380,6 +1381,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double /* mess with compression parameters */ cParams.windowLog += (FUZ_rand(&lseed) & 3) - 1; + cParams.windowLog = MIN(windowLogMax, cParams.windowLog); cParams.hashLog += (FUZ_rand(&lseed) & 3) - 1; cParams.chainLog += (FUZ_rand(&lseed) & 3) - 1; cParams.searchLog += (FUZ_rand(&lseed) & 3) - 1; From 471aa385b3f236fdab550ce5cdfbfa5e3aa9f9d5 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 26 Sep 2017 14:03:43 -0700 Subject: [PATCH 181/248] [fuzz] Speed up round trip tests * Enforce smaller maximum values for parameters * Adjust parameters to the source size The memory usage is reduced by about 5x, which makes the fuzzers run at least twice as fast, even more so with ASAN/MSAN enabled. --- tests/fuzz/block_round_trip.c | 29 ++++++--------- tests/fuzz/simple_round_trip.c | 14 +++---- tests/fuzz/stream_round_trip.c | 9 +++-- tests/fuzz/zstd_helpers.c | 68 ++++++++++++++++++++++++++-------- tests/fuzz/zstd_helpers.h | 6 ++- 5 files changed, 80 insertions(+), 46 deletions(-) diff --git a/tests/fuzz/block_round_trip.c b/tests/fuzz/block_round_trip.c index 3b3f2ff65..64ca5fc40 100644 --- a/tests/fuzz/block_round_trip.c +++ b/tests/fuzz/block_round_trip.c @@ -34,27 +34,20 @@ static size_t roundTripTest(void *result, size_t resultCapacity, void *compressed, size_t compressedCapacity, const void *src, size_t srcSize) { - int const cLevel = FUZZ_rand(&seed) % kMaxClevel; - size_t ret = ZSTD_compressBegin(cctx, cLevel); + int const cLevel = FUZZ_rand(&seed) % kMaxClevel; + ZSTD_parameters const params = ZSTD_getParams(cLevel, srcSize, 0); + size_t ret = ZSTD_compressBegin_advanced(cctx, NULL, 0, params, srcSize); + FUZZ_ZASSERT(ret); - if (ZSTD_isError(ret)) { - fprintf(stderr, "ZSTD_compressBegin() error: %s\n", - ZSTD_getErrorName(ret)); - return ret; - } - - ret = ZSTD_compressBlock(cctx, compressed, compressedCapacity, src, srcSize); - if (ZSTD_isError(ret)) { - fprintf(stderr, "ZSTD_compressBlock() error: %s\n", ZSTD_getErrorName(ret)); - return ret; - } - if (ret == 0) { + ret = ZSTD_compressBlock(cctx, compressed, compressedCapacity, src, srcSize); + FUZZ_ZASSERT(ret); + if (ret == 0) { FUZZ_ASSERT(resultCapacity >= srcSize); memcpy(result, src, srcSize); return srcSize; - } - ZSTD_decompressBegin(dctx); - return ZSTD_decompressBlock(dctx, result, resultCapacity, compressed, ret); + } + ZSTD_decompressBegin(dctx); + return ZSTD_decompressBlock(dctx, result, resultCapacity, compressed, ret); } int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) @@ -87,7 +80,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) { size_t const result = roundTripTest(rBuf, neededBufSize, cBuf, neededBufSize, src, size); - FUZZ_ASSERT_MSG(!ZSTD_isError(result), ZSTD_getErrorName(result)); + FUZZ_ZASSERT(result); FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size"); FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!"); } diff --git a/tests/fuzz/simple_round_trip.c b/tests/fuzz/simple_round_trip.c index 617e45df6..0921106de 100644 --- a/tests/fuzz/simple_round_trip.c +++ b/tests/fuzz/simple_round_trip.c @@ -41,21 +41,17 @@ static size_t roundTripTest(void *result, size_t resultCapacity, size_t err; ZSTD_CCtx_reset(cctx); - FUZZ_setRandomParameters(cctx, &seed); + FUZZ_setRandomParameters(cctx, srcSize, &seed); err = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end); - if (err != 0) { - return err; - } + FUZZ_ZASSERT(err); + FUZZ_ASSERT(err == 0); cSize = out.pos; } else { int const cLevel = FUZZ_rand(&seed) % kMaxClevel; cSize = ZSTD_compressCCtx( cctx, compressed, compressedCapacity, src, srcSize, cLevel); } - if (ZSTD_isError(cSize)) { - fprintf(stderr, "Compression error: %s\n", ZSTD_getErrorName(cSize)); - return cSize; - } + FUZZ_ZASSERT(cSize); return ZSTD_decompressDCtx(dctx, result, resultCapacity, compressed, cSize); } @@ -87,7 +83,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) { size_t const result = roundTripTest(rBuf, neededBufSize, cBuf, neededBufSize, src, size); - FUZZ_ASSERT_MSG(!ZSTD_isError(result), ZSTD_getErrorName(result)); + FUZZ_ZASSERT(result); FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size"); FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!"); } diff --git a/tests/fuzz/stream_round_trip.c b/tests/fuzz/stream_round_trip.c index e3fdd3b8f..72d70495f 100644 --- a/tests/fuzz/stream_round_trip.c +++ b/tests/fuzz/stream_round_trip.c @@ -57,7 +57,7 @@ static size_t compress(uint8_t *dst, size_t capacity, { size_t dstSize = 0; ZSTD_CCtx_reset(cctx); - FUZZ_setRandomParameters(cctx, &seed); + FUZZ_setRandomParameters(cctx, srcSize, &seed); while (srcSize > 0) { ZSTD_inBuffer in = makeInBuffer(&src, &srcSize); @@ -85,7 +85,10 @@ static size_t compress(uint8_t *dst, size_t capacity, /* Reset the compressor when the frame is finished */ if (ret == 0) { ZSTD_CCtx_reset(cctx); - FUZZ_setRandomParameters(cctx, &seed); + if ((FUZZ_rand(&seed) & 7) == 0) { + size_t const remaining = in.size - in.pos; + FUZZ_setRandomParameters(cctx, remaining, &seed); + } mode = -1; } break; @@ -146,7 +149,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) size_t const cSize = compress(cBuf, neededBufSize, src, size); size_t const rSize = ZSTD_decompressDCtx(dctx, rBuf, neededBufSize, cBuf, cSize); - FUZZ_ASSERT_MSG(!ZSTD_isError(rSize), ZSTD_getErrorName(rSize)); + FUZZ_ZASSERT(rSize); FUZZ_ASSERT_MSG(rSize == size, "Incorrect regenerated size"); FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!"); } diff --git a/tests/fuzz/zstd_helpers.c b/tests/fuzz/zstd_helpers.c index c5bef0272..602898479 100644 --- a/tests/fuzz/zstd_helpers.c +++ b/tests/fuzz/zstd_helpers.c @@ -13,30 +13,68 @@ #include "fuzz_helpers.h" #include "zstd.h" -static void setRand(ZSTD_CCtx *cctx, ZSTD_cParameter param, unsigned min, - unsigned max, uint32_t *state) { - unsigned const value = FUZZ_rand32(state, min, max); - FUZZ_ZASSERT(ZSTD_CCtx_setParameter(cctx, param, value)); +static void set(ZSTD_CCtx *cctx, ZSTD_cParameter param, unsigned value) +{ + FUZZ_ZASSERT(ZSTD_CCtx_setParameter(cctx, param, value)); } -void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, uint32_t *state) +static void setRand(ZSTD_CCtx *cctx, ZSTD_cParameter param, unsigned min, + unsigned max, uint32_t *state) { + unsigned const value = FUZZ_rand32(state, min, max); + set(cctx, param, value); +} + +ZSTD_compressionParameters FUZZ_randomCParams(size_t srcSize, uint32_t *state) { - setRand(cctx, ZSTD_p_windowLog, ZSTD_WINDOWLOG_MIN, 23, state); - setRand(cctx, ZSTD_p_hashLog, ZSTD_HASHLOG_MIN, 23, state); - setRand(cctx, ZSTD_p_chainLog, ZSTD_CHAINLOG_MIN, 24, state); - setRand(cctx, ZSTD_p_searchLog, ZSTD_SEARCHLOG_MIN, 9, state); - setRand(cctx, ZSTD_p_minMatch, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX, - state); - setRand(cctx, ZSTD_p_targetLength, ZSTD_TARGETLENGTH_MIN, - ZSTD_TARGETLENGTH_MAX, state); - setRand(cctx, ZSTD_p_compressionStrategy, ZSTD_fast, ZSTD_btultra, state); + /* Select compression parameters */ + ZSTD_compressionParameters cParams; + cParams.windowLog = FUZZ_rand32(state, ZSTD_WINDOWLOG_MIN, 15); + cParams.hashLog = FUZZ_rand32(state, ZSTD_HASHLOG_MIN, 15); + cParams.chainLog = FUZZ_rand32(state, ZSTD_CHAINLOG_MIN, 16); + cParams.searchLog = FUZZ_rand32(state, ZSTD_SEARCHLOG_MIN, 9); + cParams.searchLength = FUZZ_rand32(state, ZSTD_SEARCHLENGTH_MIN, + ZSTD_SEARCHLENGTH_MAX); + cParams.targetLength = FUZZ_rand32(state, ZSTD_TARGETLENGTH_MIN, + ZSTD_TARGETLENGTH_MAX); + cParams.strategy = FUZZ_rand32(state, ZSTD_fast, ZSTD_btultra); + return ZSTD_adjustCParams(cParams, srcSize, 0); +} + +ZSTD_frameParameters FUZZ_randomFParams(uint32_t *state) +{ + /* Select frame parameters */ + ZSTD_frameParameters fParams; + fParams.contentSizeFlag = FUZZ_rand32(state, 0, 1); + fParams.checksumFlag = FUZZ_rand32(state, 0, 1); + fParams.noDictIDFlag = FUZZ_rand32(state, 0, 1); + return fParams; +} + +ZSTD_parameters FUZZ_randomParams(size_t srcSize, uint32_t *state) +{ + ZSTD_parameters params; + params.cParams = FUZZ_randomCParams(srcSize, state); + params.fParams = FUZZ_randomFParams(state); + return params; +} + +void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, uint32_t *state) +{ + ZSTD_compressionParameters cParams = FUZZ_randomCParams(srcSize, state); + set(cctx, ZSTD_p_windowLog, cParams.windowLog); + set(cctx, ZSTD_p_hashLog, cParams.hashLog); + set(cctx, ZSTD_p_chainLog, cParams.chainLog); + set(cctx, ZSTD_p_searchLog, cParams.searchLog); + set(cctx, ZSTD_p_minMatch, cParams.searchLength); + set(cctx, ZSTD_p_targetLength, cParams.targetLength); + set(cctx, ZSTD_p_compressionStrategy, cParams.strategy); /* Select frame parameters */ setRand(cctx, ZSTD_p_contentSizeFlag, 0, 1, state); setRand(cctx, ZSTD_p_checksumFlag, 0, 1, state); setRand(cctx, ZSTD_p_dictIDFlag, 0, 1, state); /* Select long distance matchig parameters */ setRand(cctx, ZSTD_p_enableLongDistanceMatching, 0, 1, state); - setRand(cctx, ZSTD_p_ldmHashLog, ZSTD_HASHLOG_MIN, 24, state); + setRand(cctx, ZSTD_p_ldmHashLog, ZSTD_HASHLOG_MIN, 16, state); setRand(cctx, ZSTD_p_ldmMinMatch, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX, state); setRand(cctx, ZSTD_p_ldmBucketSizeLog, 0, ZSTD_LDM_BUCKETSIZELOG_MAX, diff --git a/tests/fuzz/zstd_helpers.h b/tests/fuzz/zstd_helpers.h index c2e3388a5..3856bebec 100644 --- a/tests/fuzz/zstd_helpers.h +++ b/tests/fuzz/zstd_helpers.h @@ -21,7 +21,11 @@ extern "C" { #endif -void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, uint32_t *state); +void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, uint32_t *state); + +ZSTD_compressionParameters FUZZ_randomCParams(size_t srcSize, uint32_t *state); +ZSTD_frameParameters FUZZ_randomFParams(uint32_t *state); +ZSTD_parameters FUZZ_randomParams(size_t srcSize, uint32_t *state); #ifdef __cplusplus From df4e9bba250e8e506594c8af277b7bc4775168ad Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 26 Sep 2017 14:31:06 -0700 Subject: [PATCH 182/248] fixed constant errors for gcc in c99 mode C standard does not consider a `static const int` as a constant. This is a problem for initializer, and ZSTD_STATIC_ASSERT(). Replaced by macro values --- lib/common/zstd_internal.h | 3 ++- lib/decompress/zstd_decompress.c | 2 +- lib/zstd.h | 9 +++++---- tests/fuzzer.c | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 0e34dc4c8..614bd1eab 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -105,7 +105,8 @@ static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; -static const size_t ZSTD_frameIdSize = 4; /* magic number */ +#define ZSTD_FRAMEIDSIZE 4 +static const size_t ZSTD_frameIdSize = ZSTD_FRAMEIDSIZE; /* magic number size */ #define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */ static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 7b26a7339..ffb54275e 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -278,7 +278,7 @@ static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZST size_t const minInputSize = (format==ZSTD_f_zstd1_magicless) ? ZSTD_frameHeaderSize_prefix - ZSTD_frameIdSize : ZSTD_frameHeaderSize_prefix; - ZSTD_STATIC_ASSERT(ZSTD_frameHeaderSize_prefix >= ZSTD_frameIdSize); + ZSTD_STATIC_ASSERT(ZSTD_FRAMEHEADERSIZE_PREFIX >= ZSTD_FRAMEIDSIZE); ZSTD_STATIC_ASSERT((unsigned)ZSTD_f_zstd1 < (unsigned)ZSTD_f_zstd1_magicless); assert((unsigned)format <= ZSTD_f_zstd1_magicless); /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */ if (srcSize < minInputSize) return ERROR(srcSize_wrong); diff --git a/lib/zstd.h b/lib/zstd.h index ca60088c8..3ec9af592 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -395,11 +395,12 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output #define ZSTD_LDM_MINMATCH_MAX 4096 #define ZSTD_LDM_BUCKETSIZELOG_MAX 8 -#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* for static allocation */ -#define ZSTD_FRAMEHEADERSIZE_MIN 6 -static const size_t ZSTD_frameHeaderSize_prefix = 5; /* minimum input size to know frame header size */ -static const size_t ZSTD_frameHeaderSize_max = ZSTD_FRAMEHEADERSIZE_MAX; +#define ZSTD_FRAMEHEADERSIZE_PREFIX 5 /* minimum input size to know frame header size */ +#define ZSTD_FRAMEHEADERSIZE_MIN 6 +#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* for static allocation */ +static const size_t ZSTD_frameHeaderSize_prefix = ZSTD_FRAMEHEADERSIZE_PREFIX; static const size_t ZSTD_frameHeaderSize_min = ZSTD_FRAMEHEADERSIZE_MIN; +static const size_t ZSTD_frameHeaderSize_max = ZSTD_FRAMEHEADERSIZE_MAX; static const size_t ZSTD_skippableHeaderSize = 8; /* magic number + skippable frame length */ diff --git a/tests/fuzzer.c b/tests/fuzzer.c index a341b5988..e77aab363 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -920,7 +920,7 @@ static int basicUnitTests(U32 seed, double compressibility) /* custom formats tests */ { ZSTD_CCtx* const cctx = ZSTD_createCCtx(); - static const size_t inputSize = CNBuffSize / 2; /* won't cause pb with small dict size */ + size_t const inputSize = CNBuffSize / 2; /* won't cause pb with small dict size */ /* basic block compression */ DISPLAYLEVEL(4, "test%3i : magic-less format test : ", testNb++); From 8d1e97ea9cf9edb24c65efaa3be74531f376565c Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 26 Sep 2017 15:06:30 -0700 Subject: [PATCH 183/248] minor fixes following @terrelln comments --- lib/decompress/zstd_decompress.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index ffb54275e..331ba4c64 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -279,8 +279,8 @@ static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZST ZSTD_frameHeaderSize_prefix - ZSTD_frameIdSize : ZSTD_frameHeaderSize_prefix; ZSTD_STATIC_ASSERT(ZSTD_FRAMEHEADERSIZE_PREFIX >= ZSTD_FRAMEIDSIZE); - ZSTD_STATIC_ASSERT((unsigned)ZSTD_f_zstd1 < (unsigned)ZSTD_f_zstd1_magicless); - assert((unsigned)format <= ZSTD_f_zstd1_magicless); /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */ + /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */ + assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) ); if (srcSize < minInputSize) return ERROR(srcSize_wrong); { BYTE const fhd = ((const BYTE*)src)[minInputSize-1]; @@ -315,12 +315,12 @@ static size_t ZSTD_getFrameHeader_internal(ZSTD_frameHeader* zfhPtr, const void* ZSTD_frameHeaderSize_prefix - ZSTD_frameIdSize : ZSTD_frameHeaderSize_prefix; - ZSTD_STATIC_ASSERT((unsigned)ZSTD_f_zstd1 < (unsigned)ZSTD_f_zstd1_magicless); - assert((unsigned)format <= ZSTD_f_zstd1_magicless); /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */ + /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */ + assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) ); if (srcSize < minInputSize) return minInputSize; - if (format != ZSTD_f_zstd1_magicless) - if (MEM_readLE32(src) != ZSTD_MAGICNUMBER) { + if ( (format != ZSTD_f_zstd1_magicless) + && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) { if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ if (srcSize < ZSTD_skippableHeaderSize) From 319c699991f08702a59e3e5f6c70753de0fb887d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 26 Sep 2017 15:36:14 -0700 Subject: [PATCH 184/248] created ZSTD_startingInputLength() as suggested by @terrelln --- lib/decompress/zstd_decompress.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 331ba4c64..84192b580 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -150,11 +150,19 @@ size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx) size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); } + +static size_t ZSTD_startingInputLength(ZSTD_format_e format) +{ + size_t const startingInputLength = (format==ZSTD_f_zstd1_magicless) ? + ZSTD_frameHeaderSize_prefix - ZSTD_frameIdSize : + ZSTD_frameHeaderSize_prefix; + ZSTD_STATIC_ASSERT(ZSTD_FRAMEHEADERSIZE_PREFIX >= ZSTD_FRAMEIDSIZE); + return startingInputLength; +} + size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) { - dctx->expected = (dctx->format==ZSTD_f_zstd1_magicless) ? - ZSTD_frameHeaderSize_prefix - ZSTD_frameIdSize : - ZSTD_frameHeaderSize_prefix; + dctx->expected = ZSTD_startingInputLength(dctx->format); dctx->stage = ZSTDds_getFrameHeaderSize; dctx->decodedSize = 0; dctx->previousDstEnd = NULL; @@ -267,7 +275,6 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size) return 0; } - /** ZSTD_frameHeaderSize_internal() : * srcSize must be large enough to reach header size fields. * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless @@ -275,12 +282,7 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size) * or an error code, which can be tested with ZSTD_isError() */ static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format) { - size_t const minInputSize = (format==ZSTD_f_zstd1_magicless) ? - ZSTD_frameHeaderSize_prefix - ZSTD_frameIdSize : - ZSTD_frameHeaderSize_prefix; - ZSTD_STATIC_ASSERT(ZSTD_FRAMEHEADERSIZE_PREFIX >= ZSTD_FRAMEIDSIZE); - /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */ - assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) ); + size_t const minInputSize = ZSTD_startingInputLength(format); if (srcSize < minInputSize) return ERROR(srcSize_wrong); { BYTE const fhd = ((const BYTE*)src)[minInputSize-1]; @@ -311,9 +313,7 @@ size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) static size_t ZSTD_getFrameHeader_internal(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format) { const BYTE* ip = (const BYTE*)src; - size_t const minInputSize = (format==ZSTD_f_zstd1_magicless) ? - ZSTD_frameHeaderSize_prefix - ZSTD_frameIdSize : - ZSTD_frameHeaderSize_prefix; + size_t const minInputSize = ZSTD_startingInputLength(format); /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */ assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) ); From c0dd960363d0d4c1b437b326d2461f5c4005d954 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 26 Sep 2017 15:36:57 -0700 Subject: [PATCH 185/248] switch assert() position --- lib/decompress/zstd_decompress.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 84192b580..6c142919b 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -157,6 +157,8 @@ static size_t ZSTD_startingInputLength(ZSTD_format_e format) ZSTD_frameHeaderSize_prefix - ZSTD_frameIdSize : ZSTD_frameHeaderSize_prefix; ZSTD_STATIC_ASSERT(ZSTD_FRAMEHEADERSIZE_PREFIX >= ZSTD_FRAMEIDSIZE); + /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */ + assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) ); return startingInputLength; } @@ -315,8 +317,6 @@ static size_t ZSTD_getFrameHeader_internal(ZSTD_frameHeader* zfhPtr, const void* const BYTE* ip = (const BYTE*)src; size_t const minInputSize = ZSTD_startingInputLength(format); - /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */ - assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) ); if (srcSize < minInputSize) return minInputSize; if ( (format != ZSTD_f_zstd1_magicless) From 4791561c4a0303d995dddd5f4990557c4fe012a7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 26 Sep 2017 17:57:38 -0700 Subject: [PATCH 186/248] silence minor gcc warning -Wempty-body also silence fuzz test artefacts --- lib/compress/zstdmt_compress.c | 6 ++++-- tests/fuzz/.gitignore | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 tests/fuzz/.gitignore diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index ecb799ab3..6c91d482e 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -54,7 +54,7 @@ static unsigned long long GetCurrentClockTimeMicroseconds(void) #define MUTEX_WAIT_TIME_DLEVEL 6 #define PTHREAD_MUTEX_LOCK(mutex) { \ - if (ZSTD_DEBUG>=MUTEX_WAIT_TIME_DLEVEL) { \ + if (ZSTD_DEBUG >= MUTEX_WAIT_TIME_DLEVEL) { \ unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \ pthread_mutex_lock(mutex); \ { unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \ @@ -63,7 +63,9 @@ static unsigned long long GetCurrentClockTimeMicroseconds(void) DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, "Thread took %llu microseconds to acquire mutex %s \n", \ elapsedTime, #mutex); \ } } \ - } else pthread_mutex_lock(mutex); \ + } else { \ + pthread_mutex_lock(mutex); \ + } \ } #else diff --git a/tests/fuzz/.gitignore b/tests/fuzz/.gitignore new file mode 100644 index 000000000..4ff28de98 --- /dev/null +++ b/tests/fuzz/.gitignore @@ -0,0 +1,5 @@ +# test artefacts +corpora +block_decompress +block_round_trip +simple_round_trip From cd53ac831b833790aa4b216379387ad0faa34223 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 26 Sep 2017 18:26:09 -0700 Subject: [PATCH 187/248] fixed DCtx initialization error now relying on initialization of dctx->format first --- lib/decompress/zstd_decompress.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 6c142919b..dc6ab3f3e 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -162,8 +162,10 @@ static size_t ZSTD_startingInputLength(ZSTD_format_e format) return startingInputLength; } +/* Note : this function cannot fail */ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) { + assert(dctx != NULL); dctx->expected = ZSTD_startingInputLength(dctx->format); dctx->stage = ZSTDds_getFrameHeaderSize; dctx->decodedSize = 0; @@ -174,7 +176,7 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ dctx->litEntropy = dctx->fseEntropy = 0; dctx->dictID = 0; - MEM_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue)); + ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue)); memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ dctx->LLTptr = dctx->entropy.LLTable; dctx->MLTptr = dctx->entropy.MLTable; @@ -185,6 +187,7 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) { + dctx->format = ZSTD_f_zstd1; /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */ ZSTD_decompressBegin(dctx); /* cannot fail */ dctx->staticSize = 0; dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; @@ -194,7 +197,19 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) dctx->inBuffSize = 0; dctx->outBuffSize = 0; dctx->streamStage = zdss_init; - dctx->format = ZSTD_f_zstd1; +} + +ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize) +{ + ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace; + + if ((size_t)workspace & 7) return NULL; /* 8-aligned */ + if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */ + + ZSTD_initDCtx_internal(dctx); + dctx->staticSize = workspaceSize; + dctx->inBuff = (char*)(dctx+1); + return dctx; } ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) @@ -211,19 +226,6 @@ ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) } } -ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize) -{ - ZSTD_DCtx* dctx = (ZSTD_DCtx*) workspace; - - if ((size_t)workspace & 7) return NULL; /* 8-aligned */ - if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */ - - ZSTD_initDCtx_internal(dctx); - dctx->staticSize = workspaceSize; - dctx->inBuff = (char*)(dctx+1); - return dctx; -} - ZSTD_DCtx* ZSTD_createDCtx(void) { return ZSTD_createDCtx_advanced(ZSTD_defaultCMem); From ca306c1c84df962fbfc066cdba8b6d409f20e3c2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 00:39:41 -0700 Subject: [PATCH 188/248] fixed a bug in zstreamtest decoder output buffer would receive a wrong size. In previous version, ZSTD_decompressStream() would blindly trust the caller that pos <= size. In this version, this condition is actively checked, and the function returns an error code if this condition is not respected. This check could also be done with an assert(), but since this is a user-facing interface, it seems better to keep this check at runtime. --- lib/decompress/zstd_decompress.c | 12 ++++++++++-- tests/zstreamtest.c | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index dc6ab3f3e..0380f6a10 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -2404,8 +2404,16 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB U32 someMoreWork = 1; DEBUGLOG(5, "ZSTD_decompressStream"); - if (input->pos > input->size) return ERROR(GENERIC); /* forbidden */ - if (output->pos > output->size) return ERROR(GENERIC); /* forbidden */ + if (input->pos > input->size) { /* forbidden */ + DEBUGLOG(5, "in: pos: %u vs size: %u", + (U32)input->pos, (U32)input->size); + return ERROR(GENERIC); + } + if (output->pos > output->size) { /* forbidden */ + DEBUGLOG(5, "out: pos: %u vs size: %u", + (U32)output->pos, (U32)output->size); + return ERROR(GENERIC); + } DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos)); #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 613a879bf..1f682038f 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -914,7 +914,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog); size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize); inBuff.size = inBuff.pos + readCSrcSize; - outBuff.size = inBuff.pos + dstBuffSize; + outBuff.size = outBuff.pos + dstBuffSize; decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff); if (ZSTD_getErrorCode(decompressionResult) == ZSTD_error_checksum_wrong) { DISPLAY("checksum error : \n"); From bfabd1d4dc4a9dea8fd9fb2d3e50560383aedc90 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 01:01:11 -0700 Subject: [PATCH 189/248] fixed zstreamtest decoding error same error (wrong output buffer size) was present on --mt and --new_api tests. --- tests/zstreamtest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 1f682038f..4bb486f86 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1178,7 +1178,7 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog); size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize); inBuff.size = inBuff.pos + readCSrcSize; - outBuff.size = inBuff.pos + dstBuffSize; + outBuff.size = outBuff.pos + dstBuffSize; DISPLAYLEVEL(5, "ZSTD_decompressStream input %u bytes \n", (U32)readCSrcSize); decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff); CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult)); @@ -1505,7 +1505,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog); size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize); inBuff.size = inBuff.pos + readCSrcSize; - outBuff.size = inBuff.pos + dstBuffSize; + outBuff.size = outBuff.pos + dstBuffSize; DISPLAYLEVEL(5, "ZSTD_decompressStream input %u bytes (pos:%u/%u)\n", (U32)readCSrcSize, (U32)inBuff.pos, (U32)cSize); decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff); From d56a350402ca8ad895195d41f4855799e82ca720 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 10:29:31 -0700 Subject: [PATCH 190/248] removed unsupported formats --- lib/zstd.h | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/lib/zstd.h b/lib/zstd.h index 3ec9af592..ff7802693 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -928,7 +928,7 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); * Initially, the API favored names like ZSTD_setCCtxParameter() . * In this proposal, convention is changed towards ZSTD_CCtx_setParameter() . * The main driver is that it identifies more clearly the target object type. - * It feels clearer in light of potential variants : + * It feels clearer when considering multiple targets : * ZSTD_CDict_setParameter() (rather than ZSTD_setCDictParameter()) * ZSTD_CCtxParams_setParameter() (rather than ZSTD_setCCtxParamsParameter() ) * etc... @@ -938,30 +938,19 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); * All enum will be pinned to explicit values before reaching "stable API" status */ typedef enum { - /* should we have a ZSTD_f_auto ? - * for the time being, it would mean exactly the same as ZSTD_f_zstd1. - * But, in the future, if several formats are supported, - * on the compression side, it would mean "default format", - * and on the decompression side, it would mean "multi format" - * while ZSTD_f_zstd1 could be reserved to mean "accept only zstd frames". - * Another option could be to define different enums for compression and decompression. - * This question could also be kept for later, but there is also the question of pinning the enum value, - * and pinning the value `0` is especially important */ - ZSTD_f_zstd1 = 0, /* Normal zstd frame format, specified in zstd_compression_format.md (default) */ + /* Question : should we have a format ZSTD_f_auto ? + * For the time being, it would mean exactly the same as ZSTD_f_zstd1. + * But, in the future, should several formats be supported, + * on the compression side, it would mean "default format". + * On the decompression side, it would mean "multi format", + * and ZSTD_f_zstd1 could be reserved to mean "accept *only* zstd frames". + * Since meaning is a little different, another option could be to define different enums for compression and decompression. + * This question could be kept for later, when there are actually multiple formats to support, + * but there is also the question of pinning enum values, and pinning value `0` is especially important */ + ZSTD_f_zstd1 = 0, /* zstd frame format, specified in zstd_compression_format.md (default) */ ZSTD_f_zstd1_magicless, /* Variant of zstd frame format, without initial 4-bytes magic number. * Useful to save 4 bytes per generated frame. - * Decoder will not be able to recognise this format, requiring instructions. */ - ZSTD_f_zstd1_headerless, /* Not Implemented Yet ! Complex decoder setting ! Might be removed before release */ - /* Variant of zstd frame format, without any frame header; - * Other metadata, like block size or frame checksum, are still generated. - * Useful to save between 6 and ZSTD_frameHeaderSize_max bytes per generated frame. - * However, required decoding parameters will have to be saved or known by some mechanism. - * Decoder will not be able to recognise this format, requiring instructions and parameters. */ - ZSTD_f_zstd1_block /* Not Implemented Yet ! Might be removed before release */ - /* Generate a zstd compressed block, without any metadata. - * Note that size of block content must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB. - * See ZSTD_compressBlock() for more details. - * Resulting compressed block can be decoded with ZSTD_decompressBlock(). */ + * Decoder cannot recognise automatically this format, requiring instructions. */ } ZSTD_format_e; typedef enum { From 9416195221552d6fc8b44b899360d3d14f7401ea Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 10:35:56 -0700 Subject: [PATCH 191/248] changed error code when pos<=size condition is not respected Now pointing towards src_size or dst_size, instead of error_GENERIC. --- lib/common/error_private.c | 5 +++-- lib/common/zstd_errors.h | 3 ++- lib/decompress/zstd_decompress.c | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/common/error_private.c b/lib/common/error_private.c index 8045e445e..11f7cdab1 100644 --- a/lib/common/error_private.c +++ b/lib/common/error_private.c @@ -30,14 +30,15 @@ const char* ERR_getErrorString(ERR_enum code) case PREFIX(init_missing): return "Context should be init first"; case PREFIX(memory_allocation): return "Allocation error : not enough memory"; case PREFIX(stage_wrong): return "Operation not authorized at current processing stage"; - case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; - case PREFIX(srcSize_wrong): return "Src size is incorrect"; case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; case PREFIX(dictionary_wrong): return "Dictionary mismatch"; case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples"; + case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; + case PREFIX(srcSize_wrong): return "Src size is incorrect"; + /* following error codes are not stable and may be removed or changed in a future version */ case PREFIX(frameIndex_tooLarge): return "Frame index is too large"; case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking"; case PREFIX(maxCode): diff --git a/lib/common/zstd_errors.h b/lib/common/zstd_errors.h index bde4304c9..4bcb7769f 100644 --- a/lib/common/zstd_errors.h +++ b/lib/common/zstd_errors.h @@ -63,9 +63,10 @@ typedef enum { ZSTD_error_memory_allocation = 64, ZSTD_error_dstSize_tooSmall = 70, ZSTD_error_srcSize_wrong = 72, + /* following error codes are not stable and may be removed or changed in a future version */ ZSTD_error_frameIndex_tooLarge = 100, ZSTD_error_seekableIO = 102, - ZSTD_error_maxCode = 120 /* never EVER use this value directly, it may change in future versions! Use ZSTD_isError() instead */ + ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */ } ZSTD_ErrorCode; /*! ZSTD_getErrorCode() : diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 0380f6a10..332bf860d 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -2407,12 +2407,12 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB if (input->pos > input->size) { /* forbidden */ DEBUGLOG(5, "in: pos: %u vs size: %u", (U32)input->pos, (U32)input->size); - return ERROR(GENERIC); + return ERROR(srcSize_wrong); } if (output->pos > output->size) { /* forbidden */ DEBUGLOG(5, "out: pos: %u vs size: %u", (U32)output->pos, (U32)output->size); - return ERROR(GENERIC); + return ERROR(dstSize_tooSmall); } DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos)); From ecf1778e23edc42ac6ddeb19151005ee4a08343c Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 11:19:21 -0700 Subject: [PATCH 192/248] updated ZSTD_format_e value validation also updated manual --- doc/zstd_manual.html | 24 ++++++++++++------------ lib/compress/zstd_compress.c | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/zstd_manual.html b/doc/zstd_manual.html index 15b1afea1..f1d161f37 100644 --- a/doc/zstd_manual.html +++ b/doc/zstd_manual.html @@ -786,19 +786,19 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long

    New advanced API (experimental)

    
     
     
    typedef enum {
    -    ZSTD_f_zstd1 = 0,        /* Normal zstd frame format, specified in zstd_compression_format.md (default) */
    +    /* Question : should we have a format ZSTD_f_auto ?
    +     * For the time being, it would mean exactly the same as ZSTD_f_zstd1.
    +     * But, in the future, should several formats be supported,
    +     * on the compression side, it would mean "default format".
    +     * On the decompression side, it would mean "multi format",
    +     * and ZSTD_f_zstd1 could be reserved to mean "accept *only* zstd frames".
    +     * Since meaning is a little different, another option could be to define different enums for compression and decompression.
    +     * This question could be kept for later, when there are actually multiple formats to support,
    +     * but there is also the question of pinning enum values, and pinning value `0` is especially important */
    +    ZSTD_f_zstd1 = 0,        /* zstd frame format, specified in zstd_compression_format.md (default) */
         ZSTD_f_zstd1_magicless,  /* Variant of zstd frame format, without initial 4-bytes magic number.
                                   * Useful to save 4 bytes per generated frame.
    -                              * Decoder will not be able to recognise this format, requiring instructions. */
    -    ZSTD_f_zstd1_headerless, /* Variant of zstd frame format, without any frame header;
    -                              * Other metadata, like block size or frame checksum, are still generated.
    -                              * Useful to save between 6 and ZSTD_frameHeaderSize_max bytes per generated frame.
    -                              * However, required decoding parameters will have to be saved or known by some mechanism.
    -                              * Decoder will not be able to recognise this format, requiring instructions and parameters. */
    -    ZSTD_f_zstd1_block       /* Generate a zstd compressed block, without any metadata.
    -                              * Note that size of block content must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB.
    -                              * See ZSTD_compressBlock() for more details.
    -                              * Resulting compressed block can be decoded with ZSTD_decompressBlock(). */
    +                              * Decoder cannot recognise automatically this format, requiring instructions. */
     } ZSTD_format_e;
     

    typedef enum {
    @@ -1154,7 +1154,7 @@ size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t
      
     


    -
    void ZSTD_DCtx_reset(ZSTD_DCtx* dctx);   /* Not ready yet ! */
    +
    void ZSTD_DCtx_reset(ZSTD_DCtx* dctx);
     

    Return a DCtx to clean state. If a decompression was ongoing, any internal data not yet flushed is cancelled. All parameters are back to default values, including sticky ones. diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 47def6b3b..7061d1f6f 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -330,7 +330,7 @@ size_t ZSTD_CCtxParam_setParameter( switch(param) { case ZSTD_p_format : - if (value > (unsigned)ZSTD_f_zstd1_block) + if (value > (unsigned)ZSTD_f_zstd1) return ERROR(parameter_unsupported); params->format = (ZSTD_format_e)value; return 0; From 6c41adfb28dc3b8497d401ec8994b305eb563cc0 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 27 Sep 2017 11:16:24 -0700 Subject: [PATCH 193/248] [libzstd] pthread function prefixed with ZSTD_ * `sed -i 's/pthread_/ZSTD_pthread_/g' lib/{,common,compress,decompress,dictBuilder}/*.[hc]` * Fix up `lib/common/threading.[hc]` * `sed -i s/PTHREAD_MUTEX_LOCK/ZSTD_PTHREAD_MUTEX_LOCK/g lib/compress/zstdmt_compress.c` --- lib/common/pool.c | 60 +++++++++++----------- lib/common/threading.c | 12 ++--- lib/common/threading.h | 72 +++++++++++++++----------- lib/compress/zstdmt_compress.c | 92 +++++++++++++++++----------------- lib/dictBuilder/cover.c | 28 +++++------ 5 files changed, 140 insertions(+), 124 deletions(-) diff --git a/lib/common/pool.c b/lib/common/pool.c index 5f19f331b..9e6f802e8 100644 --- a/lib/common/pool.c +++ b/lib/common/pool.c @@ -33,7 +33,7 @@ typedef struct POOL_job_s { struct POOL_ctx_s { ZSTD_customMem customMem; /* Keep track of the threads */ - pthread_t *threads; + ZSTD_pthread_t *threads; size_t numThreads; /* The queue is a circular buffer */ @@ -48,11 +48,11 @@ struct POOL_ctx_s { int queueEmpty; /* The mutex protects the queue */ - pthread_mutex_t queueMutex; + ZSTD_pthread_mutex_t queueMutex; /* Condition variable for pushers to wait on when the queue is full */ - pthread_cond_t queuePushCond; + ZSTD_pthread_cond_t queuePushCond; /* Condition variables for poppers to wait on when the queue is empty */ - pthread_cond_t queuePopCond; + ZSTD_pthread_cond_t queuePopCond; /* Indicates if the queue is shutting down */ int shutdown; }; @@ -67,14 +67,14 @@ static void* POOL_thread(void* opaque) { if (!ctx) { return NULL; } for (;;) { /* Lock the mutex and wait for a non-empty queue or until shutdown */ - pthread_mutex_lock(&ctx->queueMutex); + ZSTD_pthread_mutex_lock(&ctx->queueMutex); while (ctx->queueEmpty && !ctx->shutdown) { - pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex); + ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex); } /* empty => shutting down: so stop */ if (ctx->queueEmpty) { - pthread_mutex_unlock(&ctx->queueMutex); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); return opaque; } /* Pop a job off the queue */ @@ -83,17 +83,17 @@ static void* POOL_thread(void* opaque) { ctx->numThreadsBusy++; ctx->queueEmpty = ctx->queueHead == ctx->queueTail; /* Unlock the mutex, signal a pusher, and run the job */ - pthread_mutex_unlock(&ctx->queueMutex); - pthread_cond_signal(&ctx->queuePushCond); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + ZSTD_pthread_cond_signal(&ctx->queuePushCond); job.function(job.opaque); /* If the intended queue size was 0, signal after finishing job */ if (ctx->queueSize == 1) { - pthread_mutex_lock(&ctx->queueMutex); + ZSTD_pthread_mutex_lock(&ctx->queueMutex); ctx->numThreadsBusy--; - pthread_mutex_unlock(&ctx->queueMutex); - pthread_cond_signal(&ctx->queuePushCond); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + ZSTD_pthread_cond_signal(&ctx->queuePushCond); } } } /* for (;;) */ /* Unreachable */ @@ -120,12 +120,12 @@ POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM ctx->queueTail = 0; ctx->numThreadsBusy = 0; ctx->queueEmpty = 1; - (void)pthread_mutex_init(&ctx->queueMutex, NULL); - (void)pthread_cond_init(&ctx->queuePushCond, NULL); - (void)pthread_cond_init(&ctx->queuePopCond, NULL); + (void)ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL); + (void)ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL); + (void)ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL); ctx->shutdown = 0; /* Allocate space for the thread handles */ - ctx->threads = (pthread_t*)ZSTD_malloc(numThreads * sizeof(pthread_t), customMem); + ctx->threads = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), customMem); ctx->numThreads = 0; ctx->customMem = customMem; /* Check for errors */ @@ -133,7 +133,7 @@ POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM /* Initialize the threads */ { size_t i; for (i = 0; i < numThreads; ++i) { - if (pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) { + if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) { ctx->numThreads = i; POOL_free(ctx); return NULL; @@ -148,25 +148,25 @@ POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM */ static void POOL_join(POOL_ctx *ctx) { /* Shut down the queue */ - pthread_mutex_lock(&ctx->queueMutex); + ZSTD_pthread_mutex_lock(&ctx->queueMutex); ctx->shutdown = 1; - pthread_mutex_unlock(&ctx->queueMutex); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); /* Wake up sleeping threads */ - pthread_cond_broadcast(&ctx->queuePushCond); - pthread_cond_broadcast(&ctx->queuePopCond); + ZSTD_pthread_cond_broadcast(&ctx->queuePushCond); + ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); /* Join all of the threads */ { size_t i; for (i = 0; i < ctx->numThreads; ++i) { - pthread_join(ctx->threads[i], NULL); + ZSTD_pthread_join(ctx->threads[i], NULL); } } } void POOL_free(POOL_ctx *ctx) { if (!ctx) { return; } POOL_join(ctx); - pthread_mutex_destroy(&ctx->queueMutex); - pthread_cond_destroy(&ctx->queuePushCond); - pthread_cond_destroy(&ctx->queuePopCond); + ZSTD_pthread_mutex_destroy(&ctx->queueMutex); + ZSTD_pthread_cond_destroy(&ctx->queuePushCond); + ZSTD_pthread_cond_destroy(&ctx->queuePopCond); ZSTD_free(ctx->queue, ctx->customMem); ZSTD_free(ctx->threads, ctx->customMem); ZSTD_free(ctx, ctx->customMem); @@ -176,7 +176,7 @@ size_t POOL_sizeof(POOL_ctx *ctx) { if (ctx==NULL) return 0; /* supports sizeof NULL */ return sizeof(*ctx) + ctx->queueSize * sizeof(POOL_job) - + ctx->numThreads * sizeof(pthread_t); + + ctx->numThreads * sizeof(ZSTD_pthread_t); } /** @@ -198,12 +198,12 @@ void POOL_add(void* ctxVoid, POOL_function function, void *opaque) { POOL_ctx* const ctx = (POOL_ctx*)ctxVoid; if (!ctx) { return; } - pthread_mutex_lock(&ctx->queueMutex); + ZSTD_pthread_mutex_lock(&ctx->queueMutex); { POOL_job const job = {function, opaque}; /* Wait until there is space in the queue for the new job */ while (isQueueFull(ctx) && !ctx->shutdown) { - pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex); + ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex); } /* The queue is still going => there is space */ if (!ctx->shutdown) { @@ -212,8 +212,8 @@ void POOL_add(void* ctxVoid, POOL_function function, void *opaque) { ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize; } } - pthread_mutex_unlock(&ctx->queueMutex); - pthread_cond_signal(&ctx->queuePopCond); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + ZSTD_pthread_cond_signal(&ctx->queuePopCond); } #else /* ZSTD_MULTITHREAD not defined */ diff --git a/lib/common/threading.c b/lib/common/threading.c index a82c975b2..8be8c8da9 100644 --- a/lib/common/threading.c +++ b/lib/common/threading.c @@ -35,12 +35,12 @@ int g_ZSTD_threading_useles_symbol; static unsigned __stdcall worker(void *arg) { - pthread_t* const thread = (pthread_t*) arg; + ZSTD_pthread_t* const thread = (ZSTD_pthread_t*) arg; thread->arg = thread->start_routine(thread->arg); return 0; } -int pthread_create(pthread_t* thread, const void* unused, +int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, void* (*start_routine) (void*), void* arg) { (void)unused; @@ -54,16 +54,16 @@ int pthread_create(pthread_t* thread, const void* unused, return 0; } -int _pthread_join(pthread_t * thread, void **value_ptr) +int ZSTD_pthread_join(ZSTD_pthread_t thread, void **value_ptr) { DWORD result; - if (!thread->handle) return 0; + if (!thread.handle) return 0; - result = WaitForSingleObject(thread->handle, INFINITE); + result = WaitForSingleObject(thread.handle, INFINITE); switch (result) { case WAIT_OBJECT_0: - if (value_ptr) *value_ptr = thread->arg; + if (value_ptr) *value_ptr = thread.arg; return 0; case WAIT_ABANDONED: return EINVAL; diff --git a/lib/common/threading.h b/lib/common/threading.h index 8194bc6fa..197770db2 100644 --- a/lib/common/threading.h +++ b/lib/common/threading.h @@ -44,32 +44,31 @@ extern "C" { /* mutex */ -#define pthread_mutex_t CRITICAL_SECTION -#define pthread_mutex_init(a,b) (InitializeCriticalSection((a)), 0) -#define pthread_mutex_destroy(a) DeleteCriticalSection((a)) -#define pthread_mutex_lock(a) EnterCriticalSection((a)) -#define pthread_mutex_unlock(a) LeaveCriticalSection((a)) +#define ZSTD_pthread_mutex_t CRITICAL_SECTION +#define ZSTD_pthread_mutex_init(a, b) (InitializeCriticalSection((a)), 0) +#define ZSTD_pthread_mutex_destroy(a) DeleteCriticalSection((a)) +#define ZSTD_pthread_mutex_lock(a) EnterCriticalSection((a)) +#define ZSTD_pthread_mutex_unlock(a) LeaveCriticalSection((a)) /* condition variable */ -#define pthread_cond_t CONDITION_VARIABLE -#define pthread_cond_init(a, b) (InitializeConditionVariable((a)), 0) -#define pthread_cond_destroy(a) /* No delete */ -#define pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE) -#define pthread_cond_signal(a) WakeConditionVariable((a)) -#define pthread_cond_broadcast(a) WakeAllConditionVariable((a)) +#define ZSTD_pthread_cond_t CONDITION_VARIABLE +#define ZSTD_pthread_cond_init(a, b) (InitializeConditionVariable((a)), 0) +#define ZSTD_pthread_cond_destroy(a) /* No delete */ +#define ZSTD_pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE) +#define ZSTD_pthread_cond_signal(a) WakeConditionVariable((a)) +#define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a)) -/* pthread_create() and pthread_join() */ +/* ZSTD_pthread_create() and ZSTD_pthread_join() */ typedef struct { HANDLE handle; void* (*start_routine)(void*); void* arg; -} pthread_t; +} ZSTD_pthread_t; -int pthread_create(pthread_t* thread, const void* unused, +int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, void* (*start_routine) (void*), void* arg); -#define pthread_join(a, b) _pthread_join(&(a), (b)) -int _pthread_join(pthread_t* thread, void** value_ptr); +int ZSTD_pthread_join(ZSTD_pthread_t thread, void** value_ptr); /** * add here more wrappers as required @@ -80,23 +79,40 @@ int _pthread_join(pthread_t* thread, void** value_ptr); /* === POSIX Systems === */ # include +#define ZSTD_pthread_mutex_t pthread_mutex_t +#define ZSTD_pthread_mutex_init(a, b) pthread_mutex_init((a), (b)) +#define ZSTD_pthread_mutex_destroy(a) pthread_mutex_destroy((a)) +#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock((a)) +#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock((a)) + +#define ZSTD_pthread_cond_t pthread_cond_t +#define ZSTD_pthread_cond_init(a, b) pthread_cond_init((a), (b)) +#define ZSTD_pthread_cond_destroy(a) pthread_cond_destroy((a)) +#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait((a), (b)) +#define ZSTD_pthread_cond_signal(a) pthread_cond_signal((a)) +#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast((a)) + +#define ZSTD_pthread_t pthread_t +#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) +#define ZSTD_pthread_join(a, b) pthread_join((a),(b)) + #else /* ZSTD_MULTITHREAD not defined */ /* No multithreading support */ -#define pthread_mutex_t int /* #define rather than typedef, because sometimes pthread support is implicit, resulting in duplicated symbols */ -#define pthread_mutex_init(a,b) ((void)a, 0) -#define pthread_mutex_destroy(a) -#define pthread_mutex_lock(a) -#define pthread_mutex_unlock(a) +typedef int ZSTD_pthread_mutex_t; +#define ZSTD_pthread_mutex_init(a, b) ((void)a, 0) +#define ZSTD_pthread_mutex_destroy(a) +#define ZSTD_pthread_mutex_lock(a) +#define ZSTD_pthread_mutex_unlock(a) -#define pthread_cond_t int -#define pthread_cond_init(a,b) ((void)a, 0) -#define pthread_cond_destroy(a) -#define pthread_cond_wait(a,b) -#define pthread_cond_signal(a) -#define pthread_cond_broadcast(a) +typedef int ZSTD_pthread_cond_t; +#define ZSTD_pthread_cond_init(a, b) ((void)a, 0) +#define ZSTD_pthread_cond_destroy(a) +#define ZSTD_pthread_cond_wait(a, b) +#define ZSTD_pthread_cond_signal(a) +#define ZSTD_pthread_cond_broadcast(a) -/* do not use pthread_t */ +/* do not use ZSTD_pthread_t */ #endif /* ZSTD_MULTITHREAD */ diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index ecb799ab3..3bdb98e2e 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -53,22 +53,22 @@ static unsigned long long GetCurrentClockTimeMicroseconds(void) } #define MUTEX_WAIT_TIME_DLEVEL 6 -#define PTHREAD_MUTEX_LOCK(mutex) { \ +#define ZSTD_PTHREAD_MUTEX_LOCK(mutex) { \ if (ZSTD_DEBUG>=MUTEX_WAIT_TIME_DLEVEL) { \ unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \ - pthread_mutex_lock(mutex); \ + ZSTD_pthread_mutex_lock(mutex); \ { unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \ unsigned long long const elapsedTime = (afterTime-beforeTime); \ if (elapsedTime > 1000) { /* or whatever threshold you like; I'm using 1 millisecond here */ \ DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, "Thread took %llu microseconds to acquire mutex %s \n", \ elapsedTime, #mutex); \ } } \ - } else pthread_mutex_lock(mutex); \ + } else ZSTD_pthread_mutex_lock(mutex); \ } #else -# define PTHREAD_MUTEX_LOCK(m) pthread_mutex_lock(m) +# define ZSTD_PTHREAD_MUTEX_LOCK(m) ZSTD_pthread_mutex_lock(m) # define DEBUG_PRINTHEX(l,p,n) {} #endif @@ -85,7 +85,7 @@ typedef struct buffer_s { static const buffer_t g_nullBuffer = { NULL, 0 }; typedef struct ZSTDMT_bufferPool_s { - pthread_mutex_t poolMutex; + ZSTD_pthread_mutex_t poolMutex; size_t bufferSize; unsigned totalBuffers; unsigned nbBuffers; @@ -99,7 +99,7 @@ static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbThreads, ZSTD_custo ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_calloc( sizeof(ZSTDMT_bufferPool) + (maxNbBuffers-1) * sizeof(buffer_t), cMem); if (bufPool==NULL) return NULL; - if (pthread_mutex_init(&bufPool->poolMutex, NULL)) { + if (ZSTD_pthread_mutex_init(&bufPool->poolMutex, NULL)) { ZSTD_free(bufPool, cMem); return NULL; } @@ -116,7 +116,7 @@ static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool) if (!bufPool) return; /* compatibility with free on NULL */ for (u=0; utotalBuffers; u++) ZSTD_free(bufPool->bTable[u].start, bufPool->cMem); - pthread_mutex_destroy(&bufPool->poolMutex); + ZSTD_pthread_mutex_destroy(&bufPool->poolMutex); ZSTD_free(bufPool, bufPool->cMem); } @@ -127,10 +127,10 @@ static size_t ZSTDMT_sizeof_bufferPool(ZSTDMT_bufferPool* bufPool) + (bufPool->totalBuffers - 1) * sizeof(buffer_t); unsigned u; size_t totalBufferSize = 0; - pthread_mutex_lock(&bufPool->poolMutex); + ZSTD_pthread_mutex_lock(&bufPool->poolMutex); for (u=0; utotalBuffers; u++) totalBufferSize += bufPool->bTable[u].size; - pthread_mutex_unlock(&bufPool->poolMutex); + ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); return poolSize + totalBufferSize; } @@ -146,20 +146,20 @@ static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool) { size_t const bSize = bufPool->bufferSize; DEBUGLOG(5, "ZSTDMT_getBuffer"); - pthread_mutex_lock(&bufPool->poolMutex); + ZSTD_pthread_mutex_lock(&bufPool->poolMutex); if (bufPool->nbBuffers) { /* try to use an existing buffer */ buffer_t const buf = bufPool->bTable[--(bufPool->nbBuffers)]; size_t const availBufferSize = buf.size; if ((availBufferSize >= bSize) & (availBufferSize <= 10*bSize)) { /* large enough, but not too much */ - pthread_mutex_unlock(&bufPool->poolMutex); + ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); return buf; } /* size conditions not respected : scratch this buffer, create new one */ DEBUGLOG(5, "existing buffer does not meet size conditions => freeing"); ZSTD_free(buf.start, bufPool->cMem); } - pthread_mutex_unlock(&bufPool->poolMutex); + ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); /* create new buffer */ DEBUGLOG(5, "create a new buffer"); { buffer_t buffer; @@ -175,13 +175,13 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf) { if (buf.start == NULL) return; /* compatible with release on NULL */ DEBUGLOG(5, "ZSTDMT_releaseBuffer"); - pthread_mutex_lock(&bufPool->poolMutex); + ZSTD_pthread_mutex_lock(&bufPool->poolMutex); if (bufPool->nbBuffers < bufPool->totalBuffers) { bufPool->bTable[bufPool->nbBuffers++] = buf; /* stored for later use */ - pthread_mutex_unlock(&bufPool->poolMutex); + ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); return; } - pthread_mutex_unlock(&bufPool->poolMutex); + ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); /* Reached bufferPool capacity (should not happen) */ DEBUGLOG(5, "buffer pool capacity reached => freeing "); ZSTD_free(buf.start, bufPool->cMem); @@ -206,7 +206,7 @@ static ZSTD_CCtx_params ZSTDMT_makeJobCCtxParams(ZSTD_CCtx_params const params) /* a single CCtx Pool can be invoked from multiple threads in parallel */ typedef struct { - pthread_mutex_t poolMutex; + ZSTD_pthread_mutex_t poolMutex; unsigned totalCCtx; unsigned availCCtx; ZSTD_customMem cMem; @@ -219,7 +219,7 @@ static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool) unsigned u; for (u=0; utotalCCtx; u++) ZSTD_freeCCtx(pool->cctx[u]); /* note : compatible with free on NULL */ - pthread_mutex_destroy(&pool->poolMutex); + ZSTD_pthread_mutex_destroy(&pool->poolMutex); ZSTD_free(pool, pool->cMem); } @@ -231,7 +231,7 @@ static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(unsigned nbThreads, ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_calloc( sizeof(ZSTDMT_CCtxPool) + (nbThreads-1)*sizeof(ZSTD_CCtx*), cMem); if (!cctxPool) return NULL; - if (pthread_mutex_init(&cctxPool->poolMutex, NULL)) { + if (ZSTD_pthread_mutex_init(&cctxPool->poolMutex, NULL)) { ZSTD_free(cctxPool, cMem); return NULL; } @@ -247,7 +247,7 @@ static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(unsigned nbThreads, /* only works during initialization phase, not during compression */ static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool) { - pthread_mutex_lock(&cctxPool->poolMutex); + ZSTD_pthread_mutex_lock(&cctxPool->poolMutex); { unsigned const nbThreads = cctxPool->totalCCtx; size_t const poolSize = sizeof(*cctxPool) + (nbThreads-1)*sizeof(ZSTD_CCtx*); @@ -256,7 +256,7 @@ static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool) for (u=0; ucctx[u]); } - pthread_mutex_unlock(&cctxPool->poolMutex); + ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex); return poolSize + totalCCtxSize; } } @@ -264,14 +264,14 @@ static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool) static ZSTD_CCtx* ZSTDMT_getCCtx(ZSTDMT_CCtxPool* cctxPool) { DEBUGLOG(5, "ZSTDMT_getCCtx"); - pthread_mutex_lock(&cctxPool->poolMutex); + ZSTD_pthread_mutex_lock(&cctxPool->poolMutex); if (cctxPool->availCCtx) { cctxPool->availCCtx--; { ZSTD_CCtx* const cctx = cctxPool->cctx[cctxPool->availCCtx]; - pthread_mutex_unlock(&cctxPool->poolMutex); + ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex); return cctx; } } - pthread_mutex_unlock(&cctxPool->poolMutex); + ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex); DEBUGLOG(5, "create one more CCtx"); return ZSTD_createCCtx_advanced(cctxPool->cMem); /* note : can be NULL, when creation fails ! */ } @@ -279,7 +279,7 @@ static ZSTD_CCtx* ZSTDMT_getCCtx(ZSTDMT_CCtxPool* cctxPool) static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx) { if (cctx==NULL) return; /* compatibility with release on NULL */ - pthread_mutex_lock(&pool->poolMutex); + ZSTD_pthread_mutex_lock(&pool->poolMutex); if (pool->availCCtx < pool->totalCCtx) pool->cctx[pool->availCCtx++] = cctx; else { @@ -287,7 +287,7 @@ static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx) DEBUGLOG(5, "CCtx pool overflow : free cctx"); ZSTD_freeCCtx(cctx); } - pthread_mutex_unlock(&pool->poolMutex); + ZSTD_pthread_mutex_unlock(&pool->poolMutex); } @@ -305,8 +305,8 @@ typedef struct { unsigned lastChunk; unsigned jobCompleted; unsigned jobScanned; - pthread_mutex_t* jobCompleted_mutex; - pthread_cond_t* jobCompleted_cond; + ZSTD_pthread_mutex_t* jobCompleted_mutex; + ZSTD_pthread_cond_t* jobCompleted_cond; ZSTD_CCtx_params params; const ZSTD_CDict* cdict; ZSTDMT_CCtxPool* cctxPool; @@ -373,11 +373,11 @@ _endJob: ZSTDMT_releaseCCtx(job->cctxPool, cctx); ZSTDMT_releaseBuffer(job->bufPool, job->src); job->src = g_nullBuffer; job->srcStart = NULL; - PTHREAD_MUTEX_LOCK(job->jobCompleted_mutex); + ZSTD_PTHREAD_MUTEX_LOCK(job->jobCompleted_mutex); job->jobCompleted = 1; job->jobScanned = 0; - pthread_cond_signal(job->jobCompleted_cond); - pthread_mutex_unlock(job->jobCompleted_mutex); + ZSTD_pthread_cond_signal(job->jobCompleted_cond); + ZSTD_pthread_mutex_unlock(job->jobCompleted_mutex); } @@ -395,8 +395,8 @@ struct ZSTDMT_CCtx_s { ZSTDMT_jobDescription* jobs; ZSTDMT_bufferPool* bufPool; ZSTDMT_CCtxPool* cctxPool; - pthread_mutex_t jobCompleted_mutex; - pthread_cond_t jobCompleted_cond; + ZSTD_pthread_mutex_t jobCompleted_mutex; + ZSTD_pthread_cond_t jobCompleted_cond; size_t targetSectionSize; size_t inBuffSize; size_t dictSize; @@ -459,11 +459,11 @@ ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem) ZSTDMT_freeCCtx(mtctx); return NULL; } - if (pthread_mutex_init(&mtctx->jobCompleted_mutex, NULL)) { + if (ZSTD_pthread_mutex_init(&mtctx->jobCompleted_mutex, NULL)) { ZSTDMT_freeCCtx(mtctx); return NULL; } - if (pthread_cond_init(&mtctx->jobCompleted_cond, NULL)) { + if (ZSTD_pthread_cond_init(&mtctx->jobCompleted_cond, NULL)) { ZSTDMT_freeCCtx(mtctx); return NULL; } @@ -503,8 +503,8 @@ size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx) ZSTD_free(mtctx->jobs, mtctx->cMem); ZSTDMT_freeCCtxPool(mtctx->cctxPool); ZSTD_freeCDict(mtctx->cdictLocal); - pthread_mutex_destroy(&mtctx->jobCompleted_mutex); - pthread_cond_destroy(&mtctx->jobCompleted_cond); + ZSTD_pthread_mutex_destroy(&mtctx->jobCompleted_mutex); + ZSTD_pthread_cond_destroy(&mtctx->jobCompleted_cond); ZSTD_free(mtctx, mtctx->cMem); return 0; } @@ -649,12 +649,12 @@ static size_t ZSTDMT_compress_advanced_internal( unsigned chunkID; for (chunkID=0; chunkIDjobCompleted_mutex); + ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobCompleted_mutex); while (mtctx->jobs[chunkID].jobCompleted==0) { DEBUGLOG(5, "waiting for jobCompleted signal from chunk %u", chunkID); - pthread_cond_wait(&mtctx->jobCompleted_cond, &mtctx->jobCompleted_mutex); + ZSTD_pthread_cond_wait(&mtctx->jobCompleted_cond, &mtctx->jobCompleted_mutex); } - pthread_mutex_unlock(&mtctx->jobCompleted_mutex); + ZSTD_pthread_mutex_unlock(&mtctx->jobCompleted_mutex); DEBUGLOG(5, "ready to write chunk %u ", chunkID); mtctx->jobs[chunkID].srcStart = NULL; @@ -729,12 +729,12 @@ static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs) DEBUGLOG(4, "ZSTDMT_waitForAllJobsCompleted"); while (zcs->doneJobID < zcs->nextJobID) { unsigned const jobID = zcs->doneJobID & zcs->jobIDMask; - PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex); + ZSTD_PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex); while (zcs->jobs[jobID].jobCompleted==0) { DEBUGLOG(5, "waiting for jobCompleted signal from chunk %u", zcs->doneJobID); /* we want to block when waiting for data to flush */ - pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex); + ZSTD_pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex); } - pthread_mutex_unlock(&zcs->jobCompleted_mutex); + ZSTD_pthread_mutex_unlock(&zcs->jobCompleted_mutex); zcs->doneJobID++; } } @@ -923,13 +923,13 @@ static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsi { unsigned const wJobID = zcs->doneJobID & zcs->jobIDMask; if (zcs->doneJobID == zcs->nextJobID) return 0; /* all flushed ! */ - PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex); + ZSTD_PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex); while (zcs->jobs[wJobID].jobCompleted==0) { DEBUGLOG(5, "waiting for jobCompleted signal from job %u", zcs->doneJobID); - if (!blockToFlush) { pthread_mutex_unlock(&zcs->jobCompleted_mutex); return 0; } /* nothing ready to be flushed => skip */ - pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex); /* block when nothing available to flush */ + if (!blockToFlush) { ZSTD_pthread_mutex_unlock(&zcs->jobCompleted_mutex); return 0; } /* nothing ready to be flushed => skip */ + ZSTD_pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex); /* block when nothing available to flush */ } - pthread_mutex_unlock(&zcs->jobCompleted_mutex); + ZSTD_pthread_mutex_unlock(&zcs->jobCompleted_mutex); /* compression job completed : output can be flushed */ { ZSTDMT_jobDescription job = zcs->jobs[wJobID]; if (!job.jobScanned) { diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index f6500b3d8..efdffddbf 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -711,8 +711,8 @@ ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover( * compiled with multithreaded support. */ typedef struct COVER_best_s { - pthread_mutex_t mutex; - pthread_cond_t cond; + ZSTD_pthread_mutex_t mutex; + ZSTD_pthread_cond_t cond; size_t liveJobs; void *dict; size_t dictSize; @@ -725,8 +725,8 @@ typedef struct COVER_best_s { */ static void COVER_best_init(COVER_best_t *best) { if (best==NULL) return; /* compatible with init on NULL */ - (void)pthread_mutex_init(&best->mutex, NULL); - (void)pthread_cond_init(&best->cond, NULL); + (void)ZSTD_pthread_mutex_init(&best->mutex, NULL); + (void)ZSTD_pthread_cond_init(&best->cond, NULL); best->liveJobs = 0; best->dict = NULL; best->dictSize = 0; @@ -741,11 +741,11 @@ static void COVER_best_wait(COVER_best_t *best) { if (!best) { return; } - pthread_mutex_lock(&best->mutex); + ZSTD_pthread_mutex_lock(&best->mutex); while (best->liveJobs != 0) { - pthread_cond_wait(&best->cond, &best->mutex); + ZSTD_pthread_cond_wait(&best->cond, &best->mutex); } - pthread_mutex_unlock(&best->mutex); + ZSTD_pthread_mutex_unlock(&best->mutex); } /** @@ -759,8 +759,8 @@ static void COVER_best_destroy(COVER_best_t *best) { if (best->dict) { free(best->dict); } - pthread_mutex_destroy(&best->mutex); - pthread_cond_destroy(&best->cond); + ZSTD_pthread_mutex_destroy(&best->mutex); + ZSTD_pthread_cond_destroy(&best->cond); } /** @@ -771,9 +771,9 @@ static void COVER_best_start(COVER_best_t *best) { if (!best) { return; } - pthread_mutex_lock(&best->mutex); + ZSTD_pthread_mutex_lock(&best->mutex); ++best->liveJobs; - pthread_mutex_unlock(&best->mutex); + ZSTD_pthread_mutex_unlock(&best->mutex); } /** @@ -789,7 +789,7 @@ static void COVER_best_finish(COVER_best_t *best, size_t compressedSize, } { size_t liveJobs; - pthread_mutex_lock(&best->mutex); + ZSTD_pthread_mutex_lock(&best->mutex); --best->liveJobs; liveJobs = best->liveJobs; /* If the new dictionary is better */ @@ -812,9 +812,9 @@ static void COVER_best_finish(COVER_best_t *best, size_t compressedSize, best->parameters = parameters; best->compressedSize = compressedSize; } - pthread_mutex_unlock(&best->mutex); + ZSTD_pthread_mutex_unlock(&best->mutex); if (liveJobs == 0) { - pthread_cond_broadcast(&best->cond); + ZSTD_pthread_cond_broadcast(&best->cond); } } } From 763f8b5e453c2add84541f750a7ca5ad3664bb33 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 12:09:52 -0700 Subject: [PATCH 194/248] Change c++ test to use CXX and CXXFLAGS environment variables Fix OS-X warning on compiling .c files with clang++ Also changed test name from gpptest to cpptest, since it's no longer g++ specific --- Makefile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 7baff751c..b09da547e 100644 --- a/Makefile +++ b/Makefile @@ -112,7 +112,7 @@ CMAKE_PARAMS = -DZSTD_BUILD_CONTRIB:BOOL=ON -DZSTD_BUILD_STATIC:BOOL=ON -DZSTD_B list: @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs -.PHONY: install clangtest gpptest armtest usan asan uasan +.PHONY: install clangtest armtest usan asan uasan install: @$(MAKE) -C $(ZSTDDIR) $@ @$(MAKE) -C $(PRGDIR) $@ @@ -179,8 +179,10 @@ ppcfuzz: clean ppc64fuzz: clean CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc64-static MOREFLAGS="-m64 -static" FUZZER_FLAGS=--no-big-tests $(MAKE) -C $(TESTDIR) fuzztest -gpptest: clean - CC=$(CXX) $(MAKE) -C $(PRGDIR) all CFLAGS="-O3 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror" +.PHONY: cpptest +cpptest: CXXFLAGS += -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror +cpptest: clean + $(MAKE) -C $(PRGDIR) all CC="$(CXX) -Wno-deprecated" CFLAGS="$(CXXFLAGS)" # adding -Wno-deprecated to avoid clang++ warning on dealing with C files directly gcc5test: clean gcc-5 -v From c9949327883968153470809d1e55b3d954b685f5 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 12:22:22 -0700 Subject: [PATCH 195/248] fixed ZSTD_format_e value validation --- lib/compress/zstd_compress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 7061d1f6f..8c9d4771c 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -330,7 +330,7 @@ size_t ZSTD_CCtxParam_setParameter( switch(param) { case ZSTD_p_format : - if (value > (unsigned)ZSTD_f_zstd1) + if (value > (unsigned)ZSTD_f_zstd1_magicless) return ERROR(parameter_unsupported); params->format = (ZSTD_format_e)value; return 0; From 60ca44b545b98ace8d4e84dce1fa387a49f75524 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 12:24:13 -0700 Subject: [PATCH 196/248] switched name to cxxtest --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index b09da547e..5b3f5fdf7 100644 --- a/Makefile +++ b/Makefile @@ -179,9 +179,9 @@ ppcfuzz: clean ppc64fuzz: clean CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc64-static MOREFLAGS="-m64 -static" FUZZER_FLAGS=--no-big-tests $(MAKE) -C $(TESTDIR) fuzztest -.PHONY: cpptest -cpptest: CXXFLAGS += -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror -cpptest: clean +.PHONY: cxxtest +cxxtest: CXXFLAGS += -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror +cxxtest: clean $(MAKE) -C $(PRGDIR) all CC="$(CXX) -Wno-deprecated" CFLAGS="$(CXXFLAGS)" # adding -Wno-deprecated to avoid clang++ warning on dealing with C files directly gcc5test: clean From ea1f50bf73a1f49bacfd4603e1e86d5bc0b9f31f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 13:51:05 -0700 Subject: [PATCH 197/248] removed ZSTD_decompressBegin() from ZSTD_initDCtx_internal() It does not feel "right" from a dependency perspective. ZSTD_initDCtx_internal() is triggered once, on DCtx creation, while ZSTD_decompressBegin() is invoked at the beginning of each new frame, and is also a user-facing prototype. Downside : a DCtx must be init before first usage ! This was always the intention by the way, and is documented as such. This stage is automatically done within ZSTD_decompress() and variants, and also within ZSTD_decompressStream(). Only ZSTD_decompressContinue() is impacted, it must be preceded by a ZSTD_decompressBegin(), as detailed in doc. A test has been fixed, to no longer rely on undocumented assumption that ZSTD_decompressBegin() is invoked during init. --- lib/decompress/zstd_decompress.c | 50 ++++++++++++++++---------------- tests/fullbench.c | 1 + 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 332bf860d..960d9332f 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -162,33 +162,9 @@ static size_t ZSTD_startingInputLength(ZSTD_format_e format) return startingInputLength; } -/* Note : this function cannot fail */ -size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) -{ - assert(dctx != NULL); - dctx->expected = ZSTD_startingInputLength(dctx->format); - dctx->stage = ZSTDds_getFrameHeaderSize; - dctx->decodedSize = 0; - dctx->previousDstEnd = NULL; - dctx->base = NULL; - dctx->vBase = NULL; - dctx->dictEnd = NULL; - dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ - dctx->litEntropy = dctx->fseEntropy = 0; - dctx->dictID = 0; - ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue)); - memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ - dctx->LLTptr = dctx->entropy.LLTable; - dctx->MLTptr = dctx->entropy.MLTable; - dctx->OFTptr = dctx->entropy.OFTable; - dctx->HUFptr = dctx->entropy.hufTable; - return 0; -} - static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) { dctx->format = ZSTD_f_zstd1; /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */ - ZSTD_decompressBegin(dctx); /* cannot fail */ dctx->staticSize = 0; dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; dctx->ddict = NULL; @@ -542,7 +518,8 @@ static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity, } /*! ZSTD_decodeLiteralsBlock() : - * @return : nb of bytes read from src (< srcSize ) */ + * @return : nb of bytes read from src (< srcSize ) + * note : symbol not declared but exposed for fullbench */ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */ { @@ -2003,6 +1980,29 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict return ZSTD_refDictContent(dctx, dict, dictSize); } +/* Note : this function cannot fail */ +size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) +{ + assert(dctx != NULL); + dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */ + dctx->stage = ZSTDds_getFrameHeaderSize; + dctx->decodedSize = 0; + dctx->previousDstEnd = NULL; + dctx->base = NULL; + dctx->vBase = NULL; + dctx->dictEnd = NULL; + dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ + dctx->litEntropy = dctx->fseEntropy = 0; + dctx->dictID = 0; + ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue)); + memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ + dctx->LLTptr = dctx->entropy.LLTable; + dctx->MLTptr = dctx->entropy.MLTable; + dctx->OFTptr = dctx->entropy.OFTable; + dctx->HUFptr = dctx->entropy.hufTable; + return 0; +} + size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) { CHECK_F( ZSTD_decompressBegin(dctx) ); diff --git a/tests/fullbench.c b/tests/fullbench.c index bd9dc6135..db00ce217 100644 --- a/tests/fullbench.c +++ b/tests/fullbench.c @@ -376,6 +376,7 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) skippedSize = frameHeaderSize + ZSTD_blockHeaderSize; memcpy(buff2, dstBuff+skippedSize, g_cSize-skippedSize); srcSize = srcSize > 128 KB ? 128 KB : srcSize; /* speed relative to block */ + ZSTD_decompressBegin(g_zdc); break; } case 32: /* ZSTD_decodeSeqHeaders */ From 60059df051ce5d0005c22e0f7cf74bf16afee9a3 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 15:16:27 -0700 Subject: [PATCH 198/248] shorter make test to avoid time out on travis CI Timed tests (fuzzer) are reduced Long tests are shortened (less data generated) --- tests/Makefile | 30 +++++++++++++------------- tests/playTests.sh | 52 +++++++++++++++++++++------------------------- 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index 2746c1392..fc62b9e26 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -23,18 +23,18 @@ PRGDIR = ../programs PYTHON ?= python3 TESTARTEFACT := versionsTest namespaceTest -DEBUGLEVEL= 1 -DEBUGFLAGS= -g -DZSTD_DEBUG=$(DEBUGLEVEL) -CPPFLAGS += -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/compress \ - -I$(ZSTDDIR)/dictBuilder -I$(ZSTDDIR)/deprecated -I$(PRGDIR) -CFLAGS ?= -O3 -CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ - -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \ - -Wstrict-prototypes -Wundef -Wformat-security \ - -Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \ - -Wredundant-decls -CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) -FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) +DEBUGLEVEL ?= 1 +DEBUGFLAGS = -g -DZSTD_DEBUG=$(DEBUGLEVEL) +CPPFLAGS += -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/compress \ + -I$(ZSTDDIR)/dictBuilder -I$(ZSTDDIR)/deprecated -I$(PRGDIR) +CFLAGS ?= -O3 +CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ + -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \ + -Wstrict-prototypes -Wundef -Wformat-security \ + -Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \ + -Wredundant-decls +CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) +FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) ZSTDCOMMON_FILES := $(ZSTDDIR)/common/*.c @@ -58,8 +58,8 @@ endif MULTITHREAD = $(MULTITHREAD_CPP) $(MULTITHREAD_LD) VOID = /dev/null -ZSTREAM_TESTTIME ?= -T2mn -FUZZERTEST ?= -T5mn +ZSTREAM_TESTTIME ?= -T90s +FUZZERTEST ?= -T200s ZSTDRTTEST = --test-large-data DECODECORPUS_TESTTIME ?= -T30 @@ -241,7 +241,7 @@ endif #----------------------------------------------------------------------------- -#make tests validated only for MSYS, Linux, OSX, BSD, Hurd and Solaris targets +# make tests validated only for below targets #----------------------------------------------------------------------------- ifneq (,$(filter $(HOST_OS),MSYS POSIX)) diff --git a/tests/playTests.sh b/tests/playTests.sh index b3e0b8ab8..3ed8df9ef 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -594,7 +594,6 @@ $ECHO "\n**** zstd --list/-l single frame tests ****" ./datagen > tmp1 ./datagen > tmp2 ./datagen > tmp3 -./datagen > tmp4 $ZSTD tmp* $ZSTD -l *.zst $ZSTD -lv *.zst @@ -603,9 +602,7 @@ $ZSTD --list -v *.zst $ECHO "\n**** zstd --list/-l multiple frame tests ****" cat tmp1.zst tmp2.zst > tmp12.zst -cat tmp3.zst tmp4.zst > tmp34.zst -cat tmp12.zst tmp34.zst > tmp1234.zst -cat tmp12.zst tmp4.zst > tmp124.zst +cat tmp12.zst tmp3.zst > tmp123.zst $ZSTD -l *.zst $ZSTD -lv *.zst $ZSTD --list *.zst @@ -615,7 +612,7 @@ $ECHO "\n**** zstd --list/-l error detection tests ****" ! $ZSTD -l tmp1 tmp1.zst ! $ZSTD --list tmp* ! $ZSTD -lv tmp1* -! $ZSTD --list -v tmp2 tmp23.zst +! $ZSTD --list -v tmp2 tmp12.zst $ECHO "\n**** zstd --list/-l test with null files ****" ./datagen -g0 > tmp5 @@ -644,44 +641,43 @@ if [ "$1" != "--test-large-data" ]; then fi roundTripTest -g270000000 1 -roundTripTest -g270000000 2 -roundTripTest -g270000000 3 +roundTripTest -g250000000 2 +roundTripTest -g230000000 3 roundTripTest -g140000000 -P60 4 -roundTripTest -g140000000 -P60 5 -roundTripTest -g140000000 -P60 6 +roundTripTest -g130000000 -P62 5 +roundTripTest -g120000000 -P65 6 roundTripTest -g70000000 -P70 7 -roundTripTest -g70000000 -P70 8 -roundTripTest -g70000000 -P70 9 +roundTripTest -g60000000 -P71 8 +roundTripTest -g50000000 -P73 9 roundTripTest -g35000000 -P75 10 -roundTripTest -g35000000 -P75 11 -roundTripTest -g35000000 -P75 12 +roundTripTest -g30000000 -P76 11 +roundTripTest -g25000000 -P78 12 roundTripTest -g18000013 -P80 13 roundTripTest -g18000014 -P80 14 -roundTripTest -g18000015 -P80 15 -roundTripTest -g18000016 -P80 16 -roundTripTest -g18000017 -P80 17 +roundTripTest -g18000015 -P81 15 +roundTripTest -g18000016 -P84 16 +roundTripTest -g18000017 -P88 17 roundTripTest -g18000018 -P94 18 -roundTripTest -g18000019 -P94 19 +roundTripTest -g18000019 -P96 19 -roundTripTest -g68000020 -P99 20 -roundTripTest -g6000000000 -P99 1 +roundTripTest -g5000000000 -P99 1 fileRoundTripTest -g4193M -P99 1 $ECHO "\n**** zstd long, long distance matching round-trip tests **** " roundTripTest -g0 "2 --long" roundTripTest -g270000000 "1 --long" -roundTripTest -g140000000 -P60 "5 --long" -roundTripTest -g70000000 -P70 "8 --long" +roundTripTest -g130000000 -P60 "5 --long" +roundTripTest -g35000000 -P70 "8 --long" roundTripTest -g18000001 -P80 "18 --long" fileRoundTripTest -g4100M -P99 "1 --long" # Test large window logs -roundTripTest -g4100M -P50 "1 --long=30" -roundTripTest -g4100M -P50 "1 --long --zstd=wlog=30,clog=30" +roundTripTest -g2100M -P50 "1 --long=30" +roundTripTest -g1000M -P50 "1 --long --zstd=wlog=30,clog=30" # Test parameter parsing roundTripTest -g1M -P50 "1 --long=30" " --memory=1024MB" roundTripTest -g1M -P50 "1 --long=30 --zstd=wlog=29" " --memory=512MB" @@ -692,11 +688,11 @@ roundTripTest -g1M -P50 "1 --long=30" " --zstd=wlog=29 --memory=1024MB" if [ -n "$hasMT" ] then $ECHO "\n**** zstdmt long round-trip tests **** " - roundTripTest -g99000000 -P99 "20 -T2" " " - roundTripTest -g6000000000 -P99 "1 -T2" " " - roundTripTest -g1500000000 -P97 "1 -T999" " " - fileRoundTripTest -g4195M -P98 " -T0" " " - roundTripTest -g1500000000 -P97 "1 --long=23 -T2" " " + roundTripTest -g80000000 -P99 "19 -T2" " " + roundTripTest -g5000000000 -P99 "1 -T2" " " + roundTripTest -g500000000 -P97 "1 -T999" " " + fileRoundTripTest -g4103M -P98 " -T0" " " + roundTripTest -g400000000 -P97 "1 --long=24 -T2" " " else $ECHO "\n**** no multithreading, skipping zstdmt tests **** " fi From bdd0f6f0468eae5779cceac7b36459418ddbabde Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 15:20:08 -0700 Subject: [PATCH 199/248] improved make clean in tests/fuzz --- tests/fuzz/Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/fuzz/Makefile b/tests/fuzz/Makefile index 6d2a0cfa9..d9b00fd2a 100644 --- a/tests/fuzz/Makefile +++ b/tests/fuzz/Makefile @@ -118,9 +118,10 @@ regressiontest: corpora clean: @$(MAKE) -C $(ZSTDDIR) clean - @$(RM) -f *.a *.o - @$(RM) -f simple_round_trip stream_round_trip simple_decompress stream_decompress + @$(RM) *.a *.o + @$(RM) simple_round_trip stream_round_trip simple_decompress \ + stream_decompress block_decompress block_round_trip cleanall: - @$(RM) -rf Fuzzer - @$(RM) -rf corpora + @$(RM) -r Fuzzer + @$(RM) -r corpora From b555b7ef412c6497fa1e806aa91652e852c740aa Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 27 Sep 2017 15:29:07 -0700 Subject: [PATCH 200/248] [libzstd][opt] Simplify repcode logic --- lib/compress/zstd_opt.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/compress/zstd_opt.c b/lib/compress/zstd_opt.c index fd102da2d..c47ce23ad 100644 --- a/lib/compress/zstd_opt.c +++ b/lib/compress/zstd_opt.c @@ -529,7 +529,14 @@ size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } else { opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2]; opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1]; - opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]); + /* If opt[cur].off == ZSTD_REP_MOVE_OPT, then mlen != 1. + * offset ZSTD_REP_MOVE_OPT is used for the special case + * litLength == 0, where offset 0 means something special. + * mlen == 1 means the previous byte was stored as a literal, + * so they are mutually exclusive. + */ + assert(!(opt[cur].off == ZSTD_REP_MOVE_OPT && mlen == 1)); + opt[cur].rep[0] = (opt[cur].off == ZSTD_REP_MOVE_OPT) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]); } best_mlen = minMatch; @@ -804,7 +811,8 @@ size_t ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, } else { opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2]; opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1]; - opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]); + assert(!(opt[cur].off == ZSTD_REP_MOVE_OPT && mlen == 1)); + opt[cur].rep[0] = (opt[cur].off == ZSTD_REP_MOVE_OPT) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]); } best_mlen = minMatch; From f9de54acfb27c0e02cb22abb02eb2d72cb51ea50 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 15:38:27 -0700 Subject: [PATCH 201/248] reduced memory requirements for --long tests in new --long test section --- tests/playTests.sh | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/playTests.sh b/tests/playTests.sh index 3ed8df9ef..4689dcdda 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -674,15 +674,14 @@ roundTripTest -g270000000 "1 --long" roundTripTest -g130000000 -P60 "5 --long" roundTripTest -g35000000 -P70 "8 --long" roundTripTest -g18000001 -P80 "18 --long" -fileRoundTripTest -g4100M -P99 "1 --long" # Test large window logs -roundTripTest -g2100M -P50 "1 --long=30" -roundTripTest -g1000M -P50 "1 --long --zstd=wlog=30,clog=30" +roundTripTest -g700M -P50 "1 --long=29" +roundTripTest -g600M -P50 "1 --long --zstd=wlog=29,clog=28" # Test parameter parsing -roundTripTest -g1M -P50 "1 --long=30" " --memory=1024MB" -roundTripTest -g1M -P50 "1 --long=30 --zstd=wlog=29" " --memory=512MB" -roundTripTest -g1M -P50 "1 --long=30" " --long=29 --memory=1024MB" -roundTripTest -g1M -P50 "1 --long=30" " --zstd=wlog=29 --memory=1024MB" +roundTripTest -g1M -P50 "1 --long=29" " --memory=512MB" +roundTripTest -g1M -P50 "1 --long=29 --zstd=wlog=28" " --memory=256MB" +roundTripTest -g1M -P50 "1 --long=29" " --long=28 --memory=512MB" +roundTripTest -g1M -P50 "1 --long=29" " --zstd=wlog=28 --memory=512MB" if [ -n "$hasMT" ] From 02502191e5ea2b60a88c42ed4501e8a18432d7a7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 15:48:06 -0700 Subject: [PATCH 202/248] separated --long tests between short and long tests A fast subset of these tests is now played in short test mode --- tests/playTests.sh | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/playTests.sh b/tests/playTests.sh index 4689dcdda..a4cd4ffb5 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -635,11 +635,23 @@ $ZSTD -lv tmp1.zst rm tmp* +$ECHO "\n**** zstd long distance matching tests **** " +roundTripTest -g0 " --long" +roundTripTest -g9M "2 --long" +# Test parameter parsing +roundTripTest -g1M -P50 "1 --long=29" " --memory=512MB" +roundTripTest -g1M -P50 "1 --long=29 --zstd=wlog=28" " --memory=256MB" +roundTripTest -g1M -P50 "1 --long=29" " --long=28 --memory=512MB" +roundTripTest -g1M -P50 "1 --long=29" " --zstd=wlog=28 --memory=512MB" + + if [ "$1" != "--test-large-data" ]; then $ECHO "Skipping large data tests" exit 0 fi +$ECHO "\n**** large files tests **** " + roundTripTest -g270000000 1 roundTripTest -g250000000 2 roundTripTest -g230000000 3 @@ -668,8 +680,8 @@ roundTripTest -g5000000000 -P99 1 fileRoundTripTest -g4193M -P99 1 + $ECHO "\n**** zstd long, long distance matching round-trip tests **** " -roundTripTest -g0 "2 --long" roundTripTest -g270000000 "1 --long" roundTripTest -g130000000 -P60 "5 --long" roundTripTest -g35000000 -P70 "8 --long" @@ -677,11 +689,6 @@ roundTripTest -g18000001 -P80 "18 --long" # Test large window logs roundTripTest -g700M -P50 "1 --long=29" roundTripTest -g600M -P50 "1 --long --zstd=wlog=29,clog=28" -# Test parameter parsing -roundTripTest -g1M -P50 "1 --long=29" " --memory=512MB" -roundTripTest -g1M -P50 "1 --long=29 --zstd=wlog=28" " --memory=256MB" -roundTripTest -g1M -P50 "1 --long=29" " --long=28 --memory=512MB" -roundTripTest -g1M -P50 "1 --long=29" " --zstd=wlog=28 --memory=512MB" if [ -n "$hasMT" ] From bc32b40b9808f8b6c2d4526ae9738f5240ac01f4 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 17:27:38 -0700 Subject: [PATCH 203/248] reduced zstreamtest --mt memory load adjust compression level, hence memory usage, depending on nb threads in order to run correctly on memory-starved VM. --- Makefile | 20 ++++++++++---------- tests/zstreamtest.c | 38 ++++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/Makefile b/Makefile index 5b3f5fdf7..ac53c2dd8 100644 --- a/Makefile +++ b/Makefile @@ -296,7 +296,7 @@ endif #------------------------------------------------------------------------ -#make tests validated only for MSYS, Linux, OSX, kFreeBSD and Hurd targets +# target specific tests #------------------------------------------------------------------------ ifneq (,$(filter $(HOST_OS),MSYS POSIX)) cmakebuild: @@ -306,38 +306,38 @@ cmakebuild: cd $(BUILDIR)/cmake/build ; cmake -DCMAKE_INSTALL_PREFIX:PATH=~/install_test_dir $(CMAKE_PARAMS) .. ; $(MAKE) install ; $(MAKE) uninstall c90build: clean - gcc -v + $(CC) -v CFLAGS="-std=c90" $(MAKE) allmost # will fail, due to missing support for `long long` gnu90build: clean - gcc -v + $(CC) -v CFLAGS="-std=gnu90" $(MAKE) allmost c99build: clean - gcc -v + $(CC) -v CFLAGS="-std=c99" $(MAKE) allmost gnu99build: clean - gcc -v + $(CC) -v CFLAGS="-std=gnu99" $(MAKE) allmost c11build: clean - gcc -v + $(CC) -v CFLAGS="-std=c11" $(MAKE) allmost bmix64build: clean - gcc -v + $(CC) -v CFLAGS="-O3 -mbmi -Werror" $(MAKE) -C $(TESTDIR) test bmix32build: clean - gcc -v + $(CC) -v CFLAGS="-O3 -mbmi -mx32 -Werror" $(MAKE) -C $(TESTDIR) test bmi32build: clean - gcc -v + $(CC) -v CFLAGS="-O3 -mbmi -m32 -Werror" $(MAKE) -C $(TESTDIR) test staticAnalyze: clean - gcc -v + $(CC) -v CPPFLAGS=-g scan-build --status-bugs -v $(MAKE) all endif diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 3f190f050..28259dda8 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -741,20 +741,20 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres static const U32 maxSampleLog = 19; size_t const srcBufferSize = (size_t)1<= srcBufferSize) - maxTestSize = srcBufferSize-1; + maxTestSize = MIN(maxTestSize, srcBufferSize-16); { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize; CHECK_Z( ZSTD_resetCStream(zc, pledgedSrcSize) ); } @@ -999,15 +998,16 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp U32 result = 0; U32 testNb = 0; U32 coreSeed = seed; - ZSTDMT_CCtx* zc = ZSTDMT_createCCtx(2); /* will be reset sometimes */ + U32 nbThreads = 2; + ZSTDMT_CCtx* zc = ZSTDMT_createCCtx(nbThreads); /* will be reset sometimes */ ZSTD_DStream* zd = ZSTD_createDStream(); /* will be reset sometimes */ ZSTD_DStream* const zd_noise = ZSTD_createDStream(); clock_t const startClock = clock(); const BYTE* dict=NULL; /* can keep same dict on 2 consecutive tests */ size_t dictSize = 0; U32 oldTestLog = 0; - U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel() : g_cLevelMax_smallTests; - U32 const nbThreadsMax = bigTests ? 5 : 2; + int const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests; + U32 const nbThreadsMax = bigTests ? 4 : 2; /* allocations */ cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize); @@ -1043,8 +1043,9 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp size_t maxTestSize; /* init */ - if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); } - else { DISPLAYUPDATE(2, "\r%6u ", testNb); } + if (testNb < nbTests) { + DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); + } else { DISPLAYUPDATE(2, "\r%6u ", testNb); } FUZ_rand(&coreSeed); lseed = coreSeed ^ prime32; @@ -1052,7 +1053,7 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp /* some issues can only happen when reusing states */ if ((FUZ_rand(&lseed) & 0xFF) == 131) { U32 const nbThreadsCandidate = (FUZ_rand(&lseed) % 6) + 1; - U32 const nbThreads = MIN(nbThreadsCandidate, nbThreadsMax); + nbThreads = MIN(nbThreadsCandidate, nbThreadsMax); DISPLAYLEVEL(5, "Creating new context with %u threads \n", nbThreads); ZSTDMT_freeCCtx(zc); zc = ZSTDMT_createCCtx(nbThreads); @@ -1092,11 +1093,12 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp } else { U32 const testLog = FUZ_rand(&lseed) % maxSrcLog; U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog; - U32 const cLevelCandidate = (FUZ_rand(&lseed) % - (ZSTD_maxCLevel() - - (MAX(testLog, dictLog) / 3))) + - 1; - U32 const cLevel = MIN(cLevelCandidate, cLevelMax); + int const cLevelCandidate = ( FUZ_rand(&lseed) + % (ZSTD_maxCLevel() - (MAX(testLog, dictLog) / 2)) ) + + 1; + int const cLevelThreadAdjusted = cLevelCandidate - (nbThreads * 2) + 2; /* reduce cLevel when multiple threads to reduce memory consumption */ + int const cLevelMin = MAX(cLevelThreadAdjusted, 1); /* no negative cLevel yet */ + int const cLevel = MIN(cLevelMin, cLevelMax); maxTestSize = FUZ_rLogLength(&lseed, testLog); oldTestLog = testLog; /* random dictionary selection */ From aa800c4793a4bc044df53614ca652c96d59e1078 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 27 Sep 2017 18:00:15 -0700 Subject: [PATCH 204/248] reduced memory usage of zstreamtest --newapi to run on memory-constrained VM --- tests/zstreamtest.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 28259dda8..62af8e167 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1279,8 +1279,9 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double const BYTE* dict = NULL; /* can keep same dict on 2 consecutive tests */ size_t dictSize = 0; U32 oldTestLog = 0; - U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel() : g_cLevelMax_smallTests; - U32 const nbThreadsMax = bigTests ? 5 : 1; + U32 windowLogMalus = 0; /* can survive between 2 loops */ + U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests; + U32 const nbThreadsMax = bigTests ? 4 : 2; ZSTD_CCtx_params* cctxParams = ZSTD_createCCtxParams(); /* allocations */ @@ -1388,10 +1389,14 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double cParams.chainLog += (FUZ_rand(&lseed) & 3) - 1; cParams.searchLog += (FUZ_rand(&lseed) & 3) - 1; cParams.searchLength += (FUZ_rand(&lseed) & 3) - 1; - cParams.targetLength = (U32)(cParams.targetLength * (0.5 + ((double)(FUZ_rand(&lseed) & 127) / 128))); + cParams.targetLength = (U32)((cParams.targetLength + 1 ) * (0.5 + ((double)(FUZ_rand(&lseed) & 127) / 128))); cParams = ZSTD_adjustCParams(cParams, 0, 0); - if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_windowLog, cParams.windowLog, useOpaqueAPI) ); + if (FUZ_rand(&lseed) & 1) { + CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_windowLog, cParams.windowLog, useOpaqueAPI) ); + assert(cParams.windowLog >= ZSTD_WINDOWLOG_MIN); /* guaranteed by ZSTD_adjustCParams() */ + windowLogMalus = (cParams.windowLog - ZSTD_WINDOWLOG_MIN) / 5; + } if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_hashLog, cParams.hashLog, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_chainLog, cParams.chainLog, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_searchLog, cParams.searchLog, useOpaqueAPI) ); @@ -1405,7 +1410,6 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmBucketSizeLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_LDM_BUCKETSIZELOG_MAX), useOpaqueAPI) ); if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashEveryLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN), useOpaqueAPI) ); - /* unconditionally set, to be sync with decoder */ /* mess with frame parameters */ if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_checksumFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_dictIDFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); @@ -1415,7 +1419,8 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double /* multi-threading parameters */ { U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1; - U32 const nbThreads = MIN(nbThreadsCandidate, nbThreadsMax); + U32 const nbThreadsAdjusted = (windowLogMalus < nbThreadsCandidate) ? nbThreadsCandidate - windowLogMalus : 1; + U32 const nbThreads = MIN(nbThreadsAdjusted, nbThreadsMax); CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_nbThreads, nbThreads, useOpaqueAPI) ); if (nbThreads > 1) { U32 const jobLog = FUZ_rand(&lseed) % (testLog+1); From d9c1e9125f2863a90c2910b995cb6920dc0d5734 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 27 Sep 2017 18:23:06 -0700 Subject: [PATCH 205/248] [fuzz] Small changes for oss-fuzz integration --- tests/fuzz/default.options | 2 ++ tests/fuzz/fuzz.py | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 tests/fuzz/default.options diff --git a/tests/fuzz/default.options b/tests/fuzz/default.options new file mode 100644 index 000000000..8ea858837 --- /dev/null +++ b/tests/fuzz/default.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 8192 diff --git a/tests/fuzz/fuzz.py b/tests/fuzz/fuzz.py index 9864d822d..b591e4f67 100755 --- a/tests/fuzz/fuzz.py +++ b/tests/fuzz/fuzz.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/usr/bin/env python # ################################################################ # Copyright (c) 2016-present, Facebook, Inc. @@ -757,6 +757,10 @@ def zip_cmd(args): subprocess.check_call(cmd + seeds) +def list_cmd(args): + print("\n".join(TARGETS)) + + def short_help(args): name = args[0] print("Usage: {} [OPTIONS] COMMAND [ARGS]...\n".format(name)) @@ -776,6 +780,7 @@ def help(args): print("\tgen\t\tGenerate a seed corpus for a fuzzer") print("\tminimize\tMinimize the test corpora") print("\tzip\t\tZip the minimized corpora up") + print("\tlist\t\tList the available targets") def main(): @@ -802,6 +807,8 @@ def main(): return minimize(args) if command == "zip": return zip_cmd(args) + if command == "list": + return list_cmd(args) short_help(args) print("Error: No such command {} (pass -h for help)".format(command)) return 1 From 9b5b47ac930442b24c0fb123274b5cc7a216d478 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Sep 2017 01:25:40 -0700 Subject: [PATCH 206/248] ensure adjustCParams adjust hLog and cLog even without srcSize It would previously exit when srcSize is unknown. But in the case of custom parameters, hLog and cLog can still be too large in comparison with windowLog. Reduces maximum memory allocated during zstreamtest --newapi --- lib/compress/zstd_compress.c | 21 +++++++++++++-------- lib/zstd.h | 30 +++++++++++++++--------------- tests/zstreamtest.c | 17 ++++++++++++++--- 3 files changed, 42 insertions(+), 26 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index e84149bd3..0dbe196ff 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -634,26 +634,31 @@ static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) mostly downsizing to reduce memory consumption and initialization. Both `srcSize` and `dictSize` are optional (use 0 if unknown), but if both are 0, no optimization can be done. - Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */ + Note : cPar is considered validated at this stage. Use ZSTD_checkCParams() to ensure that condition. */ ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize) { assert(ZSTD_checkCParams(cPar)==0); - if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */ - /* resize params, to use less memory when necessary */ - { U32 const minSrcSize = (srcSize==0) ? 500 : 0; + /* resize windowLog if src is small, to use less memory when necessary */ + ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == -1ULL); + if ( (dictSize || (srcSize+1 > 1)) /* srcSize test depends on static assert condition */ + && (srcSize-1 < (1ULL< srcLog) cPar.windowLog = srcLog; } } if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog; { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); - if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog); + if (cycleLog > cPar.windowLog) + cPar.chainLog -= (cycleLog - cPar.windowLog); } - if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */ + if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) + cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */ return cPar; } diff --git a/lib/zstd.h b/lib/zstd.h index b7c75d5f2..59aa0b020 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -376,22 +376,22 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output #define ZSTD_MAGIC_SKIPPABLE_START 0x184D2A50U #define ZSTD_MAGIC_DICTIONARY 0xEC30A437 /* v0.7+ */ -#define ZSTD_WINDOWLOG_MAX_32 30 -#define ZSTD_WINDOWLOG_MAX_64 31 +#define ZSTD_WINDOWLOG_MAX_32 30 +#define ZSTD_WINDOWLOG_MAX_64 31 #define ZSTD_WINDOWLOG_MAX ((unsigned)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64)) -#define ZSTD_WINDOWLOG_MIN 10 -#define ZSTD_HASHLOG_MAX MIN(ZSTD_WINDOWLOG_MAX, 30) -#define ZSTD_HASHLOG_MIN 6 -#define ZSTD_CHAINLOG_MAX MIN(ZSTD_WINDOWLOG_MAX+1, 30) -#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN -#define ZSTD_HASHLOG3_MAX 17 -#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1) -#define ZSTD_SEARCHLOG_MIN 1 -#define ZSTD_SEARCHLENGTH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */ -#define ZSTD_SEARCHLENGTH_MIN 3 /* only for ZSTD_btopt, other strategies are limited to 4 */ -#define ZSTD_TARGETLENGTH_MIN 4 -#define ZSTD_TARGETLENGTH_MAX 999 -#define ZSTD_LDM_MINMATCH_MIN 4 +#define ZSTD_WINDOWLOG_MIN 10 +#define ZSTD_HASHLOG_MAX MIN(ZSTD_WINDOWLOG_MAX, 30) +#define ZSTD_HASHLOG_MIN 6 +#define ZSTD_CHAINLOG_MAX MIN(ZSTD_WINDOWLOG_MAX+1, 30) +#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN +#define ZSTD_HASHLOG3_MAX 17 +#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1) +#define ZSTD_SEARCHLOG_MIN 1 +#define ZSTD_SEARCHLENGTH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */ +#define ZSTD_SEARCHLENGTH_MIN 3 /* only for ZSTD_btopt, other strategies are limited to 4 */ +#define ZSTD_TARGETLENGTH_MIN 4 /* only useful for btopt */ +#define ZSTD_TARGETLENGTH_MAX 999 /* only useful for btopt */ +#define ZSTD_LDM_MINMATCH_MIN 4 #define ZSTD_LDM_MINMATCH_MAX 4096 #define ZSTD_LDM_BUCKETSIZELOG_MAX 8 diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 62af8e167..0b8995c5d 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1322,6 +1322,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double else { DISPLAYUPDATE(2, "\r%6u ", testNb); } FUZ_rand(&coreSeed); lseed = coreSeed ^ prime32; + DISPLAYLEVEL(5, " *** Test %u *** \n", testNb); /* states full reset (deliberately not synchronized) */ /* some issues can only happen when reusing states */ @@ -1371,7 +1372,9 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double (MAX(testLog, dictLog) / 3))) + 1; U32 const cLevel = MIN(cLevelCandidate, cLevelMax); + DISPLAYLEVEL(5, "t%u: cLevel : %u \n", testNb, cLevel); maxTestSize = FUZ_rLogLength(&lseed, testLog); + DISPLAYLEVEL(5, "t%u: maxTestSize : %u \n", testNb, (U32)maxTestSize); oldTestLog = testLog; /* random dictionary selection */ dictSize = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0; @@ -1396,9 +1399,16 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_windowLog, cParams.windowLog, useOpaqueAPI) ); assert(cParams.windowLog >= ZSTD_WINDOWLOG_MIN); /* guaranteed by ZSTD_adjustCParams() */ windowLogMalus = (cParams.windowLog - ZSTD_WINDOWLOG_MIN) / 5; + DISPLAYLEVEL(5, "t%u: windowLog : %u \n", testNb, cParams.windowLog); + } + if (FUZ_rand(&lseed) & 1) { + CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_hashLog, cParams.hashLog, useOpaqueAPI) ); + DISPLAYLEVEL(5, "t%u: hashLog : %u \n", testNb, cParams.hashLog); + } + if (FUZ_rand(&lseed) & 1) { + CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_chainLog, cParams.chainLog, useOpaqueAPI) ); + DISPLAYLEVEL(5, "t%u: chainLog : %u \n", testNb, cParams.chainLog); } - if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_hashLog, cParams.hashLog, useOpaqueAPI) ); - if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_chainLog, cParams.chainLog, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_searchLog, cParams.searchLog, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_minMatch, cParams.searchLength, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_targetLength, cParams.targetLength, useOpaqueAPI) ); @@ -1415,13 +1425,14 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_dictIDFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_contentSizeFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) ); - DISPLAYLEVEL(5, "pledgedSrcSize : %u \n", (U32)pledgedSrcSize); + DISPLAYLEVEL(5, "t%u: pledgedSrcSize : %u \n", testNb, (U32)pledgedSrcSize); /* multi-threading parameters */ { U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1; U32 const nbThreadsAdjusted = (windowLogMalus < nbThreadsCandidate) ? nbThreadsCandidate - windowLogMalus : 1; U32 const nbThreads = MIN(nbThreadsAdjusted, nbThreadsMax); CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_nbThreads, nbThreads, useOpaqueAPI) ); + DISPLAYLEVEL(5, "t%u: nbThreads : %u \n", testNb, nbThreads); if (nbThreads > 1) { U32 const jobLog = FUZ_rand(&lseed) % (testLog+1); CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_overlapSizeLog, FUZ_rand(&lseed) % 10, useOpaqueAPI) ); From 9fe50ed6239f86d569030744f6545feb89a6d933 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Sep 2017 01:42:06 -0700 Subject: [PATCH 207/248] fixed maximum windowLog for zstreamtest --newapi for compatibility with low memory VM --- tests/zstreamtest.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 0b8995c5d..3d0ab8896 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -50,7 +50,6 @@ static const U32 g_cLevelMax_smallTests = 10; #define COMPRESSIBLE_NOISE_LENGTH (10 MB) #define FUZ_COMPRESSIBILITY_DEFAULT 50 static const U32 prime32 = 2654435761U; -static const U32 windowLogMax = 27; /*-************************************ @@ -1052,8 +1051,7 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp /* states full reset (deliberately not synchronized) */ /* some issues can only happen when reusing states */ if ((FUZ_rand(&lseed) & 0xFF) == 131) { - U32 const nbThreadsCandidate = (FUZ_rand(&lseed) % 6) + 1; - nbThreads = MIN(nbThreadsCandidate, nbThreadsMax); + nbThreads = (FUZ_rand(&lseed) % nbThreadsMax) + 1; DISPLAYLEVEL(5, "Creating new context with %u threads \n", nbThreads); ZSTDMT_freeCCtx(zc); zc = ZSTDMT_createCCtx(nbThreads); @@ -1369,7 +1367,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog; U32 const cLevelCandidate = (FUZ_rand(&lseed) % (ZSTD_maxCLevel() - - (MAX(testLog, dictLog) / 3))) + + (MAX(testLog, dictLog) / 2))) + 1; U32 const cLevel = MIN(cLevelCandidate, cLevelMax); DISPLAYLEVEL(5, "t%u: cLevel : %u \n", testNb, cLevel); @@ -1384,6 +1382,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double } { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize; ZSTD_compressionParameters cParams = ZSTD_getCParams(cLevel, pledgedSrcSize, dictSize); + static const U32 windowLogMax = 25; /* mess with compression parameters */ cParams.windowLog += (FUZ_rand(&lseed) & 3) - 1; From d6770f80af091f208c2bfc2f49281984b00be52b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Sep 2017 02:14:48 -0700 Subject: [PATCH 208/248] minor : rewrite unit tests using CHECK_Z macro --- lib/compress/zstdmt_compress.c | 5 +- tests/zstreamtest.c | 111 ++++++++++++++------------------- 2 files changed, 49 insertions(+), 67 deletions(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index ecb799ab3..202d61b6a 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -985,7 +985,7 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, assert(output->pos <= output->size); assert(input->pos <= input->size); if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) { - /* current frame being ended. Only flush/end are allowed. Or start new frame with init */ + /* current frame being ended. Only flush/end are allowed */ return ERROR(stage_wrong); } if (mtctx->params.nbThreads==1) { /* delegate to single-thread (synchronous) */ @@ -1014,7 +1014,8 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, if (input->size > input->pos) { /* support NULL input */ if (mtctx->inBuff.buffer.start == NULL) { mtctx->inBuff.buffer = ZSTDMT_getBuffer(mtctx->bufPool); - if (mtctx->inBuff.buffer.start == NULL) return ERROR(memory_allocation); + if (mtctx->inBuff.buffer.start == NULL) + return ERROR(memory_allocation); mtctx->inBuff.filled = 0; } { size_t const toLoad = MIN(input->size - input->pos, mtctx->inBuffSize - mtctx->inBuff.filled); diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 3d0ab8896..acaf8f962 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -96,6 +96,15 @@ unsigned int FUZ_rand(unsigned int* seedPtr) return rand32 >> 5; } +#define CHECK_Z(f) { \ + size_t const err = f; \ + if (ZSTD_isError(err)) { \ + DISPLAY("Error => %s : %s ", \ + #f, ZSTD_getErrorName(err)); \ + DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); \ + goto _output_error; \ +} } + /*====================================================== * Basic Unit tests @@ -166,8 +175,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo RDG_genBuffer(CNBuffer, CNBufferSize, compressibility, 0., seed); /* Create dictionary */ - MEM_STATIC_ASSERT(COMPRESSIBLE_NOISE_LENGTH >= 4 MB); - dictionary = FUZ_createDictionary(CNBuffer, 4 MB, 4 KB, 40 KB); + dictionary = FUZ_createDictionary(CNBuffer, CNBufferSize, 4 KB, 40 KB); if (!dictionary.start) { DISPLAY("Error creating dictionary, aborting \n"); goto _output_error; @@ -181,16 +189,14 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo /* Basic compression test */ DISPLAYLEVEL(3, "test%3i : compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH); - { size_t const r = ZSTD_initCStream_usingDict(zc, CNBuffer, dictSize, 1); - if (ZSTD_isError(r)) goto _output_error; } + CHECK_Z( ZSTD_initCStream_usingDict(zc, CNBuffer, dictSize, 1) ); outBuff.dst = (char*)(compressedBuffer)+cSize; outBuff.size = compressedBufferSize; outBuff.pos = 0; inBuff.src = CNBuffer; inBuff.size = CNBufferSize; inBuff.pos = 0; - { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); - if (ZSTD_isError(r)) goto _output_error; } + CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) ); if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */ { size_t const r = ZSTD_endStream(zc, &outBuff); if (r != 0) goto _output_error; } /* error, or some data not flushed */ @@ -225,8 +231,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo /* skippable frame test */ DISPLAYLEVEL(3, "test%3i : decompress skippable frame : ", testNb++); - if (ZSTD_isError( ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize) )) - goto _output_error; + CHECK_Z( ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize) ); inBuff.src = compressedBuffer; inBuff.size = cSize; inBuff.pos = 0; @@ -244,8 +249,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo inBuff2 = inBuff; DISPLAYLEVEL(3, "test%3i : decompress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH); ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize); - { size_t const r = ZSTD_setDStreamParameter(zd, DStream_p_maxWindowSize, 1000000000); /* large limit */ - if (ZSTD_isError(r)) goto _output_error; } + CHECK_Z( ZSTD_setDStreamParameter(zd, DStream_p_maxWindowSize, 1000000000) ); /* large limit */ { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff); if (remaining != 0) goto _output_error; } /* should reach end of frame == 0; otherwise, some data left, or an error */ if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */ @@ -335,8 +339,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo inBuff.src = CNBuffer; inBuff.size = CNBufferSize; inBuff.pos = 0; - { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); - if (ZSTD_isError(r)) goto _output_error; } + CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) ); if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */ { size_t const r = ZSTD_endStream(zc, &outBuff); if (r != 0) goto _output_error; } /* error, or some data not flushed */ @@ -353,8 +356,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo inBuff.src = CNBuffer; inBuff.size = CNBufferSize; inBuff.pos = 0; - { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); - if (ZSTD_isError(r)) goto _output_error; } + CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) ); if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */ { size_t const r = ZSTD_endStream(zc, &outBuff); if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; /* must fail : wrong srcSize */ @@ -376,8 +378,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo outBuff.size = ZSTD_compressBound(inSize); outBuff.pos = 0; DISPLAYLEVEL(5, "compress1 "); - { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); - if (ZSTD_isError(r)) goto _output_error; } + CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) ); if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */ DISPLAYLEVEL(5, "end1 "); { size_t const r = ZSTD_endStream(zc, &outBuff); @@ -394,8 +395,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo outBuff.size = ZSTD_compressBound(inSize); outBuff.pos = 0; DISPLAYLEVEL(5, "compress2 "); - { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); - if (ZSTD_isError(r)) goto _output_error; } + CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) ); if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */ DISPLAYLEVEL(5, "end2 "); { size_t const r = ZSTD_endStream(zc, &outBuff); @@ -415,8 +415,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo inBuff.src = CNBuffer; inBuff.size = CNBufferSize; inBuff.pos = 0; - { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); - if (ZSTD_isError(r)) goto _output_error; } + CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) ); if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */ { size_t const r = ZSTD_endStream(zc, &outBuff); if (r != 0) goto _output_error; } /* error, or some data not flushed */ @@ -465,8 +464,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo /* Memory restriction */ DISPLAYLEVEL(3, "test%3i : maxWindowSize < frame requirement : ", testNb++); ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize); - { size_t const r = ZSTD_setDStreamParameter(zd, DStream_p_maxWindowSize, 1000); /* too small limit */ - if (ZSTD_isError(r)) goto _output_error; } + CHECK_Z( ZSTD_setDStreamParameter(zd, DStream_p_maxWindowSize, 1000) ); /* too small limit */ inBuff.src = compressedBuffer; inBuff.size = cSize; inBuff.pos = 0; @@ -490,8 +488,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo inBuff.src = CNBuffer; inBuff.size = CNBufferSize; inBuff.pos = 0; - { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); - if (ZSTD_isError(r)) goto _output_error; } + CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) ); if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */ { size_t const r = ZSTD_endStream(zc, &outBuff); if (r != 0) goto _output_error; } /* error, or some data not flushed */ @@ -513,16 +510,14 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo } DISPLAYLEVEL(3, "test%3i : compress with ZSTD_CCtx_refPrefix : ", testNb++); - { size_t const refErr = ZSTD_CCtx_refPrefix(zc, dictionary.start, dictionary.filled); - if (ZSTD_isError(refErr)) goto _output_error; } + CHECK_Z( ZSTD_CCtx_refPrefix(zc, dictionary.start, dictionary.filled) ); outBuff.dst = compressedBuffer; outBuff.size = compressedBufferSize; outBuff.pos = 0; inBuff.src = CNBuffer; inBuff.size = CNBufferSize; inBuff.pos = 0; - { size_t const r = ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end); - if (ZSTD_isError(r)) goto _output_error; } + CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end) ); if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */ cSize = outBuff.pos; DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBufferSize*100); @@ -549,23 +544,20 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo inBuff.src = CNBuffer; inBuff.size = CNBufferSize; inBuff.pos = 0; - { size_t const r = ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end); - if (ZSTD_isError(r)) goto _output_error; } + CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end) ); if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */ cSize = outBuff.pos; DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBufferSize*100); DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should work): ", testNb++); - { size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize); - if (ZSTD_isError(r)) goto _output_error; /* must fail : dictionary not used */ - DISPLAYLEVEL(3, "OK \n"); - } + CHECK_Z( ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize) ); + DISPLAYLEVEL(3, "OK \n"); /* Empty srcSize */ DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced with pledgedSrcSize=0 and dict : ", testNb++); { ZSTD_parameters params = ZSTD_getParams(5, 0, 0); params.fParams.contentSizeFlag = 1; - ZSTD_initCStream_advanced(zc, dictionary.start, dictionary.filled, params, 0); + CHECK_Z( ZSTD_initCStream_advanced(zc, dictionary.start, dictionary.filled, params, 0) ); } /* cstream advanced shall write content size = 0 */ inBuff.src = CNBuffer; inBuff.size = 0; @@ -573,7 +565,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo outBuff.dst = compressedBuffer; outBuff.size = compressedBufferSize; outBuff.pos = 0; - if (ZSTD_isError(ZSTD_compressStream(zc, &outBuff, &inBuff))) goto _output_error; + CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) ); if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error; cSize = outBuff.pos; if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error; @@ -582,7 +574,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo DISPLAYLEVEL(3, "test%3i : pledgedSrcSize == 0 behaves properly : ", testNb++); { ZSTD_parameters params = ZSTD_getParams(5, 0, 0); params.fParams.contentSizeFlag = 1; - ZSTD_initCStream_advanced(zc, NULL, 0, params, 0); + CHECK_Z( ZSTD_initCStream_advanced(zc, NULL, 0, params, 0) ); } /* cstream advanced shall write content size = 0 */ inBuff.src = CNBuffer; inBuff.size = 0; @@ -590,7 +582,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo outBuff.dst = compressedBuffer; outBuff.size = compressedBufferSize; outBuff.pos = 0; - if (ZSTD_isError(ZSTD_compressStream(zc, &outBuff, &inBuff))) goto _output_error; + CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) ); if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error; cSize = outBuff.pos; if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error; @@ -602,7 +594,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo outBuff.dst = compressedBuffer; outBuff.size = compressedBufferSize; outBuff.pos = 0; - if (ZSTD_isError(ZSTD_compressStream(zc, &outBuff, &inBuff))) goto _output_error; + CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) ); if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error; cSize = outBuff.pos; if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != ZSTD_CONTENTSIZE_UNKNOWN) goto _output_error; @@ -610,17 +602,16 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo /* Basic multithreading compression test */ DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads : ", testNb++, COMPRESSIBLE_NOISE_LENGTH); - { ZSTD_parameters const params = ZSTD_getParams(1, 0, 0); - size_t const r = ZSTDMT_initCStream_advanced(mtctx, CNBuffer, dictSize, params, CNBufferSize); - if (ZSTD_isError(r)) goto _output_error; } + { ZSTD_parameters const params = ZSTD_getParams(1, 0, 0); + CHECK_Z( ZSTDMT_initCStream_advanced(mtctx, CNBuffer, dictSize, params, CNBufferSize) ); + } outBuff.dst = (char*)(compressedBuffer); outBuff.size = compressedBufferSize; outBuff.pos = 0; inBuff.src = CNBuffer; inBuff.size = CNBufferSize; inBuff.pos = 0; - { size_t const r = ZSTDMT_compressStream_generic(mtctx, &outBuff, &inBuff, ZSTD_e_end); - if (ZSTD_isError(r)) goto _output_error; } + CHECK_Z( ZSTDMT_compressStream_generic(mtctx, &outBuff, &inBuff, ZSTD_e_end) ); if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */ { size_t const r = ZSTDMT_endStream(mtctx, &outBuff); if (r != 0) goto _output_error; } /* error, or some data not flushed */ @@ -641,9 +632,10 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo "\x28\xB5\x2F\xFD\x04\x00\x4C\x00\x00\x10\x61\x61\x01\x00\x00\x2A" "\x80\x05\x44\x00\x00\x08\x62\x01\x00\x00\x2A\x20\x04\x5D\x00\x00" "\x00\x03\x40\x00\x00\x64\x60\x27\xB0\xE0\x0C\x67\x62\xCE\xE0"; - ZSTD_DStream* zds = ZSTD_createDStream(); + ZSTD_DStream* const zds = ZSTD_createDStream(); + if (zds==NULL) goto _output_error; - ZSTD_initDStream(zds); + CHECK_Z( ZSTD_initDStream(zds) ); inBuff.src = testCase; inBuff.size = 47; inBuff.pos = 0; @@ -652,9 +644,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo outBuff.pos = 0; while (inBuff.pos < inBuff.size) { - size_t const r = ZSTD_decompressStream(zds, &outBuff, &inBuff); - /* Bug will cause checksum to fail */ - if (ZSTD_isError(r)) goto _output_error; + CHECK_Z( ZSTD_decompressStream(zds, &outBuff, &inBuff) ); } ZSTD_freeDStream(zds); @@ -725,15 +715,6 @@ static U32 FUZ_randomClampedLength(U32* seed, U32 minVal, U32 maxVal) goto _output_error; \ } } -#define CHECK_Z(f) { \ - size_t const err = f; \ - if (ZSTD_isError(err)) { \ - DISPLAY("Error => %s : %s ", \ - #f, ZSTD_getErrorName(err)); \ - DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); \ - goto _output_error; \ -} } - static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests) { U32 const maxSrcLog = bigTests ? 24 : 22; @@ -1482,7 +1463,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double outBuff.size = outBuff.pos + dstBuffSize; CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, flush) ); - DISPLAYLEVEL(5, "compress consumed %u bytes (total : %u) \n", + DISPLAYLEVEL(6, "compress consumed %u bytes (total : %u) \n", (U32)inBuff.pos, (U32)(totalTestSize + inBuff.pos)); XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos); @@ -1497,11 +1478,11 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1); size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize); outBuff.size = outBuff.pos + adjustedDstSize; - DISPLAYLEVEL(5, "End-flush into dst buffer of size %u \n", (U32)adjustedDstSize); + DISPLAYLEVEL(6, "End-flush into dst buffer of size %u \n", (U32)adjustedDstSize); remainingToFlush = ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end); - CHECK(ZSTD_isError(remainingToFlush), - "ZSTD_compress_generic w/ ZSTD_e_end error : %s", - ZSTD_getErrorName(remainingToFlush) ); + CHECK( ZSTD_isError(remainingToFlush), + "ZSTD_compress_generic w/ ZSTD_e_end error : %s", + ZSTD_getErrorName(remainingToFlush) ); } } crcOrig = XXH64_digest(&xxhState); cSize = outBuff.pos; @@ -1525,11 +1506,11 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize); inBuff.size = inBuff.pos + readCSrcSize; outBuff.size = inBuff.pos + dstBuffSize; - DISPLAYLEVEL(5, "ZSTD_decompressStream input %u bytes (pos:%u/%u)\n", + DISPLAYLEVEL(6, "ZSTD_decompressStream input %u bytes (pos:%u/%u)\n", (U32)readCSrcSize, (U32)inBuff.pos, (U32)cSize); decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff); CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult)); - DISPLAYLEVEL(5, "inBuff.pos = %u \n", (U32)readCSrcSize); + DISPLAYLEVEL(6, "inBuff.pos = %u \n", (U32)readCSrcSize); } CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (U32)outBuff.pos, (U32)totalTestSize); CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (U32)inBuff.pos, (U32)cSize); From 377abcc02c9db9cec4f348a04a1caaa45cfa13a7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Sep 2017 02:23:44 -0700 Subject: [PATCH 209/248] zstdmt : better behavior when freeing a context right after a memory allocation error wait for all jobs to be completed, so that freeing can happen safely --- lib/compress/zstdmt_compress.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 202d61b6a..5001f4a00 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -1014,8 +1014,10 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, if (input->size > input->pos) { /* support NULL input */ if (mtctx->inBuff.buffer.start == NULL) { mtctx->inBuff.buffer = ZSTDMT_getBuffer(mtctx->bufPool); - if (mtctx->inBuff.buffer.start == NULL) + if (mtctx->inBuff.buffer.start == NULL) { + ZSTDMT_waitForAllJobsCompleted(mtctx); return ERROR(memory_allocation); + } mtctx->inBuff.filled = 0; } { size_t const toLoad = MIN(input->size - input->pos, mtctx->inBuffSize - mtctx->inBuff.filled); From 2cd15dd9a426a4dea70c4dac100410efbc81fbc4 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Sep 2017 02:33:41 -0700 Subject: [PATCH 210/248] fixed minor Visual conversion warning --- lib/compress/zstd_compress.c | 2 +- lib/compress/zstdmt_compress.c | 35 ++++++++++++++++++---------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 0dbe196ff..eff6c57c6 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -640,7 +640,7 @@ ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameter assert(ZSTD_checkCParams(cPar)==0); /* resize windowLog if src is small, to use less memory when necessary */ - ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == -1ULL); + ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (0ULL - 1)); if ( (dictSize || (srcSize+1 > 1)) /* srcSize test depends on static assert condition */ && (srcSize-1 < (1ULL<allJobsCompleted = 1; } +static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs) +{ + DEBUGLOG(4, "ZSTDMT_waitForAllJobsCompleted"); + while (zcs->doneJobID < zcs->nextJobID) { + unsigned const jobID = zcs->doneJobID & zcs->jobIDMask; + PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex); + while (zcs->jobs[jobID].jobCompleted==0) { + DEBUGLOG(5, "waiting for jobCompleted signal from chunk %u", zcs->doneJobID); /* we want to block when waiting for data to flush */ + pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex); + } + pthread_mutex_unlock(&zcs->jobCompleted_mutex); + zcs->doneJobID++; + } +} + size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx) { if (mtctx==NULL) return 0; /* compatible with free on NULL */ POOL_free(mtctx->factory); - if (!mtctx->allJobsCompleted) ZSTDMT_releaseAllJobResources(mtctx); /* stop workers first */ + if (!mtctx->allJobsCompleted) { + ZSTDMT_waitForAllJobsCompleted(mtctx); + ZSTDMT_releaseAllJobResources(mtctx); /* stop workers first */ + } ZSTDMT_freeBufferPool(mtctx->bufPool); /* release job resources into pools first */ ZSTD_free(mtctx->jobs, mtctx->cMem); ZSTDMT_freeCCtxPool(mtctx->cctxPool); @@ -724,21 +742,6 @@ size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx, /* ======= Streaming API ======= */ /* ====================================== */ -static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs) -{ - DEBUGLOG(4, "ZSTDMT_waitForAllJobsCompleted"); - while (zcs->doneJobID < zcs->nextJobID) { - unsigned const jobID = zcs->doneJobID & zcs->jobIDMask; - PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex); - while (zcs->jobs[jobID].jobCompleted==0) { - DEBUGLOG(5, "waiting for jobCompleted signal from chunk %u", zcs->doneJobID); /* we want to block when waiting for data to flush */ - pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex); - } - pthread_mutex_unlock(&zcs->jobCompleted_mutex); - zcs->doneJobID++; - } -} - size_t ZSTDMT_initCStream_internal( ZSTDMT_CCtx* zcs, const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode, From 8074261d00045ca7f677d0750ac5c01d5a13f9f9 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Sep 2017 11:46:19 -0700 Subject: [PATCH 211/248] zstdmt : move on when not enough memory for a new input buffer just continue operations without input forward progress, instead of an error that stops current compression session. --- lib/compress/zstd_compress.c | 2 +- lib/compress/zstdmt_compress.c | 23 +++++++++++------------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index eff6c57c6..117a1f58b 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -642,7 +642,7 @@ ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameter /* resize windowLog if src is small, to use less memory when necessary */ ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (0ULL - 1)); if ( (dictSize || (srcSize+1 > 1)) /* srcSize test depends on static assert condition */ - && (srcSize-1 < (1ULL<dictSize + mtctx->targetSectionSize; + unsigned forwardInputProgress = 0; assert(output->pos <= output->size); assert(input->pos <= input->size); if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) { @@ -995,10 +996,10 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp); } - /* single-pass shortcut (note : this is synchronous-mode) */ - if ( (mtctx->nextJobID==0) /* just started */ - && (mtctx->inBuff.filled==0) /* nothing buffered */ - && (endOp==ZSTD_e_end) /* end order */ + /* single-pass shortcut (note : synchronous-mode) */ + if ( (mtctx->nextJobID == 0) /* just started */ + && (mtctx->inBuff.filled == 0) /* nothing buffered */ + && (endOp == ZSTD_e_end) /* end order */ && (output->size - output->pos >= ZSTD_compressBound(input->size - input->pos)) ) { /* enough room */ size_t const cSize = ZSTDMT_compress_advanced_internal(mtctx, (char*)output->dst + output->pos, output->size - output->pos, @@ -1016,18 +1017,16 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, /* fill input buffer */ if (input->size > input->pos) { /* support NULL input */ if (mtctx->inBuff.buffer.start == NULL) { - mtctx->inBuff.buffer = ZSTDMT_getBuffer(mtctx->bufPool); - if (mtctx->inBuff.buffer.start == NULL) { - ZSTDMT_waitForAllJobsCompleted(mtctx); - return ERROR(memory_allocation); - } + mtctx->inBuff.buffer = ZSTDMT_getBuffer(mtctx->bufPool); /* note : may fail, in which case, no forward input progress */ mtctx->inBuff.filled = 0; } - { size_t const toLoad = MIN(input->size - input->pos, mtctx->inBuffSize - mtctx->inBuff.filled); + if (mtctx->inBuff.buffer.start) { + size_t const toLoad = MIN(input->size - input->pos, mtctx->inBuffSize - mtctx->inBuff.filled); DEBUGLOG(5, "inBuff:%08X; inBuffSize=%u; ToCopy=%u", (U32)(size_t)mtctx->inBuff.buffer.start, (U32)mtctx->inBuffSize, (U32)toLoad); memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, toLoad); input->pos += toLoad; mtctx->inBuff.filled += toLoad; + forwardInputProgress = toLoad>0; } } if ( (mtctx->inBuff.filled >= newJobThreshold) /* filled enough : let's compress */ @@ -1036,7 +1035,7 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, } /* check for potential compressed data ready to be flushed */ - CHECK_F( ZSTDMT_flushNextJob(mtctx, output, (mtctx->inBuff.filled == mtctx->inBuffSize) /* blockToFlush */) ); /* block if it wasn't possible to create new job due to saturation */ + CHECK_F( ZSTDMT_flushNextJob(mtctx, output, !forwardInputProgress /* blockToFlush */) ); /* block if there was no forward input progress */ if (input->pos < input->size) /* input not consumed : do not flush yet */ endOp = ZSTD_e_continue; From bbef058ae6f2e931c9af59b6da4f1f666775fb23 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Sep 2017 11:48:45 -0700 Subject: [PATCH 212/248] zstreamtest --newapi : reduced maximum allocated memory --- tests/zstreamtest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index acaf8f962..f69cdd646 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1363,7 +1363,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double } { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize; ZSTD_compressionParameters cParams = ZSTD_getCParams(cLevel, pledgedSrcSize, dictSize); - static const U32 windowLogMax = 25; + static const U32 windowLogMax = 24; /* mess with compression parameters */ cParams.windowLog += (FUZ_rand(&lseed) & 3) - 1; From b93598d6a4b50c85f43e59803afe31d6ac84a6b0 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Sep 2017 13:49:12 -0700 Subject: [PATCH 213/248] zstdmt : reduced maximum nb of threads to avoid memory address space issues on 32-bits systems (see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=876416#17) --- lib/compress/zstdmt_compress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index b15bf05af..a653704ab 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -10,7 +10,7 @@ /* ====== Tuning parameters ====== */ -#define ZSTDMT_NBTHREADS_MAX 256 +#define ZSTDMT_NBTHREADS_MAX 200 #define ZSTDMT_OVERLAPLOG_DEFAULT 6 From 5705d9f25a48c6af18d7e2b8430d99b64540c90d Mon Sep 17 00:00:00 2001 From: "W. Felix Handte" Date: Thu, 21 Sep 2017 17:30:43 -0700 Subject: [PATCH 214/248] Add basic tests for the lz4 integration --- .travis.yml | 2 ++ Makefile | 5 +++++ tests/Makefile | 22 ++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/.travis.yml b/.travis.yml index a52d57af3..26aeab90c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,8 @@ matrix: - env: Cmd='make ppcinstall && make ppcfuzz' - env: Cmd='make ppcinstall && make ppc64fuzz' + - env: Cmd='make lz4install && make -C tests test-lz4' + git: depth: 1 diff --git a/Makefile b/Makefile index e8bdcea33..13e825021 100644 --- a/Makefile +++ b/Makefile @@ -97,6 +97,7 @@ clean: @$(MAKE) -C examples/ $@ > $(VOID) @$(MAKE) -C contrib/gen_html $@ > $(VOID) @$(RM) zstd$(EXT) zstdmt$(EXT) tmp* + @$(RM) -r lz4 @echo Cleaning completed #------------------------------------------------------------------------------ @@ -274,6 +275,10 @@ gpp6install: apt-add-repo clang38install: APT_PACKAGES="clang-3.8" $(MAKE) apt-install +# Ubuntu 14.04 ships a too-old lz4 +lz4install: + [ -e lz4 ] || git clone https://github.com/lz4/lz4 && sudo $(MAKE) -C lz4 install + endif diff --git a/tests/Makefile b/tests/Makefile index 2746c1392..f30398c06 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -374,4 +374,26 @@ test-decodecorpus-cli: decodecorpus test-pool: poolTests $(QEMU_SYS) ./poolTests +test-lz4: ZSTD = LD_LIBRARY_PATH=/usr/local/lib $(PRGDIR)/zstd +test-lz4: zstd decodecorpus + ./decodecorpus -ptmp + # lz4 -> zstd + lz4 < tmp | \ + $(ZSTD) -d | \ + cmp - tmp + # zstd -> lz4 + $(ZSTD) --format=lz4 < tmp | \ + lz4 -d | \ + cmp - tmp + # zstd -> zstd + $(ZSTD) --format=lz4 < tmp | \ + $(ZSTD) -d | \ + cmp - tmp + # zstd -> zstd + $(ZSTD) < tmp | \ + $(ZSTD) -d | \ + cmp - tmp + + rm tmp + endif From d0519d4b0cc88ae965bcfffb2efbee7f2eda425d Mon Sep 17 00:00:00 2001 From: "W. Felix Handte" Date: Thu, 28 Sep 2017 19:18:15 -0400 Subject: [PATCH 215/248] Add CLI Program Name Detection for LZ4 --- programs/zstdcli.c | 4 ++++ tests/Makefile | 13 ++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 89e97c294..20a1b2171 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -61,6 +61,8 @@ #define ZSTD_UNLZMA "unlzma" #define ZSTD_XZ "xz" #define ZSTD_UNXZ "unxz" +#define ZSTD_LZ4 "lz4" +#define ZSTD_UNLZ4 "unlz4" #define KB *(1 <<10) #define MB *(1 <<20) @@ -425,6 +427,8 @@ int main(int argCount, const char* argv[]) if (exeNameMatch(programName, ZSTD_UNLZMA)) { operation=zom_decompress; FIO_setCompressionType(FIO_lzmaCompression); FIO_setRemoveSrcFile(1); } /* behave like unlzma */ if (exeNameMatch(programName, ZSTD_XZ)) { suffix = XZ_EXTENSION; FIO_setCompressionType(FIO_xzCompression); FIO_setRemoveSrcFile(1); } /* behave like xz */ if (exeNameMatch(programName, ZSTD_UNXZ)) { operation=zom_decompress; FIO_setCompressionType(FIO_xzCompression); FIO_setRemoveSrcFile(1); } /* behave like unxz */ + if (exeNameMatch(programName, ZSTD_LZ4)) { suffix = LZ4_EXTENSION; FIO_setCompressionType(FIO_lz4Compression); FIO_setRemoveSrcFile(1); } /* behave like xz */ + if (exeNameMatch(programName, ZSTD_UNLZ4)) { operation=zom_decompress; FIO_setCompressionType(FIO_lz4Compression); FIO_setRemoveSrcFile(1); } /* behave like unxz */ memset(&compressionParams, 0, sizeof(compressionParams)); /* command switches */ diff --git a/tests/Makefile b/tests/Makefile index f30398c06..0741170c7 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -375,16 +375,27 @@ test-pool: poolTests $(QEMU_SYS) ./poolTests test-lz4: ZSTD = LD_LIBRARY_PATH=/usr/local/lib $(PRGDIR)/zstd +test-lz4: ZSTD_LZ4 = LD_LIBRARY_PATH=/usr/local/lib ./lz4 +test-lz4: ZSTD_UNLZ4 = LD_LIBRARY_PATH=/usr/local/lib ./unlz4 test-lz4: zstd decodecorpus + ln -s $(PRGDIR)/zstd lz4 + ln -s $(PRGDIR)/zstd unlz4 + ./decodecorpus -ptmp # lz4 -> zstd lz4 < tmp | \ $(ZSTD) -d | \ cmp - tmp + lz4 < tmp | \ + $(ZSTD_UNLZ4) | \ + cmp - tmp # zstd -> lz4 $(ZSTD) --format=lz4 < tmp | \ lz4 -d | \ cmp - tmp + $(ZSTD_LZ4) < tmp | \ + lz4 -d | \ + cmp - tmp # zstd -> zstd $(ZSTD) --format=lz4 < tmp | \ $(ZSTD) -d | \ @@ -394,6 +405,6 @@ test-lz4: zstd decodecorpus $(ZSTD) -d | \ cmp - tmp - rm tmp + rm tmp lz4 unlz4 endif From dc27c36495a01aae9802cef57ad666bcd4cd08e5 Mon Sep 17 00:00:00 2001 From: "W. Felix Handte" Date: Thu, 28 Sep 2017 19:34:39 -0400 Subject: [PATCH 216/248] Update documentation to reflect other format support --- programs/README.md | 10 ++++++++++ programs/zstd.1 | 14 +++++++++++--- programs/zstd.1.md | 4 ++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/programs/README.md b/programs/README.md index 2aae52588..2da9a6db1 100644 --- a/programs/README.md +++ b/programs/README.md @@ -40,6 +40,16 @@ There are however other Makefile targets that create different variations of CLI In which case, linking stage will fail if `lzma` library cannot be found. This might be useful to prevent silent feature disabling. +- __HAVE_LZ4__ : `zstd` can compress and decompress files in `.lz4` formats. + This is ordered through commands `--format=lz4`. + Alternatively, symlinks named `lz4`, or `unlz4` will mimic intended behavior. + `.lz4` support is automatically enabled when `lz4` library is detected at build time. + It's possible to disable `.lz4` support, by setting HAVE_LZ4=0 . + Example : make zstd HAVE_LZ4=0 + It's also possible to force compilation with lz4 support, using HAVE_LZ4=1. + In which case, linking stage will fail if `lz4` library cannot be found. + This might be useful to prevent silent feature disabling. + - __ZSTD_LEGACY_SUPPORT__ : `zstd` can decompress files compressed by older versions of `zstd`. Starting v0.8.0, all versions of `zstd` produce frames compliant with the [specification](../doc/zstd_compression_format.md), and are therefore compatible. But older versions (< v0.8.0) produced different, incompatible, frames. diff --git a/programs/zstd.1 b/programs/zstd.1 index 0fad1d277..423195203 100644 --- a/programs/zstd.1 +++ b/programs/zstd.1 @@ -60,11 +60,11 @@ In most places where an integer argument is expected, an optional suffix is supp . .TP \fBKiB\fR -Multiply the integer by 1,024 (2^10)\. \fBKi\fR, \fBK\fR, and \fBKB\fR are accepted as synonyms for \fBKiB\fR\. +Multiply the integer by 1,024 (2\e \fBKi\fR, \fBK\fR, and \fBKB\fR are accepted as synonyms for \fBKiB\fR\. . .TP \fBMiB\fR -Multiply the integer by 1,048,576 (2^20)\. \fBMi\fR, \fBM\fR, and \fBMB\fR are accepted as synonyms for \fBMiB\fR\. +Multiply the integer by 1,048,576 (2\e \fBMi\fR, \fBM\fR, and \fBMB\fR are accepted as synonyms for \fBMiB\fR\. . .SS "Operation mode" If multiple operation mode options are given, the last one takes effect\. @@ -148,6 +148,10 @@ keep source file(s) after successful compression or decompression\. This is the operate recursively on dictionaries . .TP +\fB\-\-format=FORMAT\fR +compress and decompress in other formats\. If compiled with support, zstd can compress to or decompress from other compression algorithm formats\. Possibly available options are \fBgzip\fR, \fBxz\fR, \fBlzma\fR, and \fBlz4\fR\. +. +.TP \fB\-h\fR/\fB\-H\fR, \fB\-\-help\fR display help/long help and exit . @@ -190,6 +194,10 @@ Dictionary saved into \fBfile\fR (default name: dictionary)\. Limit dictionary to specified size (default: 112640)\. . .TP +\fB\-B#\fR +Split input files in blocks of size # (default: no split) +. +.TP \fB\-\-dictID=#\fR A dictionary ID is a locally unique ID that a decoder can use to verify it is using the right dictionary\. By default, zstd will create a 4\-bytes random number ID\. It\'s possible to give a precise number instead\. Short numbers have an advantage : an ID < 256 will only need 1 byte in the compressed frame header, and an ID < 65536 will only need 2 bytes\. This compares favorably to 4 bytes default\. However, it\'s up to the dictionary manager to not assign twice the same ID to 2 different dictionaries\. . @@ -340,7 +348,7 @@ Bigger hash tables usually improve compression ratio at the expense of more memo The minimum \fIldmhlog\fR is 6 and the maximum is 26 (default: 20)\. . .TP -\fBldmSearchLength\fR=\fIldmslen\fR, \fBldmSlen\fR=\fIldmslen\fR +\fBldmSearchLength\fR=\fIldmslen\fR, \fBldmslen\fR=\fIldmslen\fR Specify the minimum searched length of a match for long distance matching\. . .IP diff --git a/programs/zstd.1.md b/programs/zstd.1.md index e446422b6..b10c1c4bb 100644 --- a/programs/zstd.1.md +++ b/programs/zstd.1.md @@ -143,6 +143,10 @@ the last one takes effect. This is the default behavior. * `-r`: operate recursively on dictionaries +* `--format=FORMAT`: + compress and decompress in other formats. If compiled with + support, zstd can compress to or decompress from other compression algorithm + formats. Possibly available options are `gzip`, `xz`, `lzma`, and `lz4`. * `-h`/`-H`, `--help`: display help/long help and exit * `-V`, `--version`: From 86b4fe5b45458c65f26762fb1de2803056e3d37e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Sep 2017 18:14:28 -0700 Subject: [PATCH 217/248] adjustCParams : restored previous behavior unknowns srcSize presumed small if there is a dictionary (dictSize>0) and presumed large otherwise. --- lib/common/pool.c | 10 +++++----- lib/compress/zstd_compress.c | 33 ++++++++++++++++++--------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/lib/common/pool.c b/lib/common/pool.c index 9e6f802e8..1b0fe1035 100644 --- a/lib/common/pool.c +++ b/lib/common/pool.c @@ -99,16 +99,16 @@ static void* POOL_thread(void* opaque) { /* Unreachable */ } -POOL_ctx *POOL_create(size_t numThreads, size_t queueSize) { +POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); } -POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) { - POOL_ctx *ctx; +POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) { + POOL_ctx* ctx; /* Check the parameters */ if (!numThreads) { return NULL; } /* Allocate the context and zero initialize */ - ctx = (POOL_ctx *)ZSTD_calloc(sizeof(POOL_ctx), customMem); + ctx = (POOL_ctx*)ZSTD_calloc(sizeof(POOL_ctx), customMem); if (!ctx) { return NULL; } /* Initialize the job queue. * It needs one extra space since one space is wasted to differentiate empty @@ -146,7 +146,7 @@ POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM /*! POOL_join() : Shutdown the queue, wake any sleeping threads, and join all of the threads. */ -static void POOL_join(POOL_ctx *ctx) { +static void POOL_join(POOL_ctx* ctx) { /* Shut down the queue */ ZSTD_pthread_mutex_lock(&ctx->queueMutex); ctx->shutdown = 1; diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 7e2dbffd2..4c2254abe 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -640,26 +640,29 @@ static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) /** ZSTD_adjustCParams_internal() : optimize `cPar` for a given input (`srcSize` and `dictSize`). - mostly downsizing to reduce memory consumption and initialization. - Both `srcSize` and `dictSize` are optional (use 0 if unknown), - but if both are 0, no optimization can be done. + mostly downsizing to reduce memory consumption and initialization latency. + Both `srcSize` and `dictSize` are optional (use 0 if unknown). Note : cPar is considered validated at this stage. Use ZSTD_checkCParams() to ensure that condition. */ ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize) { + static const U64 minSrcSize = 513; /* (1<<9) + 1 */ + static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); assert(ZSTD_checkCParams(cPar)==0); - /* resize windowLog if src is small, to use less memory when necessary */ - ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (0ULL - 1)); - if ( (dictSize || (srcSize+1 > 1)) /* srcSize test depends on static assert condition */ - && (srcSize-1 < (1ULL< srcLog) cPar.windowLog = srcLog; - } } + if (dictSize && (srcSize+1<2) /* srcSize unknown */ ) + srcSize = minSrcSize; /* presumed small when there is a dictionary */ + else + srcSize -= 1; /* unknown 0 => -1ULL : presumed large */ + + /* resize windowLog if input is small enough, to use less memory */ + if ( (srcSize < maxWindowResize) + && (dictSize < maxWindowResize) ) { + U32 const tSize = (U32)(srcSize + dictSize); + static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN; + U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN : + ZSTD_highbit32(tSize-1) + 1; + if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; + } if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog; { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); if (cycleLog > cPar.windowLog) From 47c6a95d0786edad1910a62b620babe739fe218f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Sep 2017 18:27:22 -0700 Subject: [PATCH 218/248] zstreamtest : run unit tests only during "normal" session not during --mt, --newapi and --opaque this avoids running them 4x during `make test` --- tests/zstreamtest.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 6ae4ef96c..16f514425 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1614,9 +1614,9 @@ int main(int argc, const char** argv) /* Parsing commands. Aggregated commands are allowed */ if (argument[0]=='-') { - if (!strcmp(argument, "--mt")) { selected_api=mt_api; continue; } - if (!strcmp(argument, "--newapi")) { selected_api=advanced_api; continue; } - if (!strcmp(argument, "--opaqueapi")) { selected_api=advanced_api; useOpaqueAPI = 1; continue; } + if (!strcmp(argument, "--mt")) { selected_api=mt_api; testNb += !testNb; continue; } + if (!strcmp(argument, "--newapi")) { selected_api=advanced_api; testNb += !testNb; continue; } + if (!strcmp(argument, "--opaqueapi")) { selected_api=advanced_api; testNb += !testNb; useOpaqueAPI = 1; continue; } if (!strcmp(argument, "--no-big-tests")) { bigTests=0; continue; } argument++; From e0065cf660cdc1b66f8cb9bae65fac9f8ad63797 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Sep 2017 18:34:38 -0700 Subject: [PATCH 219/248] make test : removed zstreamtest unit tests for variants slightly reduced time to create dictionary at beginning of unit tests --- tests/Makefile | 6 +++--- tests/zstreamtest.c | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index fc62b9e26..95c33bc4b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -316,9 +316,9 @@ test-zbuff32: zbufftest32 test-zstream: zstreamtest $(QEMU_SYS) ./zstreamtest $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) - $(QEMU_SYS) ./zstreamtest --mt $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) - $(QEMU_SYS) ./zstreamtest --newapi $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) - $(QEMU_SYS) ./zstreamtest --opaqueapi $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) + $(QEMU_SYS) ./zstreamtest --mt -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) + $(QEMU_SYS) ./zstreamtest --newapi -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) + $(QEMU_SYS) ./zstreamtest --opaqueapi -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) test-zstream32: zstreamtest32 $(QEMU_SYS) ./zstreamtest32 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 16f514425..8b4c83694 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -175,7 +175,8 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo RDG_genBuffer(CNBuffer, CNBufferSize, compressibility, 0., seed); /* Create dictionary */ - dictionary = FUZ_createDictionary(CNBuffer, CNBufferSize, 4 KB, 40 KB); + DISPLAYLEVEL(3, "creating dictionary for unit tests \n"); + dictionary = FUZ_createDictionary(CNBuffer, CNBufferSize / 2, 8 KB, 40 KB); if (!dictionary.start) { DISPLAY("Error creating dictionary, aborting \n"); goto _output_error; From 754ae5cc0bc47e96bc30163c007295859dc04c29 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Sep 2017 20:44:22 -0700 Subject: [PATCH 220/248] removed ZSTDMT_waitForAllJobsCompleted() from ZSTDMT_freeCCtx() as per @terrelln comment --- lib/compress/zstdmt_compress.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index bc7d1e540..bfa1c42da 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -514,13 +514,10 @@ static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs) size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx) { if (mtctx==NULL) return 0; /* compatible with free on NULL */ - POOL_free(mtctx->factory); - if (!mtctx->allJobsCompleted) { - ZSTDMT_waitForAllJobsCompleted(mtctx); - ZSTDMT_releaseAllJobResources(mtctx); /* stop workers first */ - } - ZSTDMT_freeBufferPool(mtctx->bufPool); /* release job resources into pools first */ + POOL_free(mtctx->factory); /* stop and free worker threads */ + ZSTDMT_releaseAllJobResources(mtctx); /* release job resources into pools first */ ZSTD_free(mtctx->jobs, mtctx->cMem); + ZSTDMT_freeBufferPool(mtctx->bufPool); ZSTDMT_freeCCtxPool(mtctx->cctxPool); ZSTD_freeCDict(mtctx->cdictLocal); ZSTD_pthread_mutex_destroy(&mtctx->jobCompleted_mutex); From e963800e27ee85354bfba462685fc2cd0c2ac819 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Sep 2017 23:01:31 -0700 Subject: [PATCH 221/248] zstdmt : fixed : buffer dst0 wasn't properly set to null after usage now it's possible to unconditionnally invoke ZSTD_releaseAllJobRessources() wether previous compression was completed correctly or not. --- lib/compress/zstdmt_compress.c | 13 +++++++++---- tests/fuzzer.c | 3 +-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index bfa1c42da..03871421c 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -115,9 +115,12 @@ static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbThreads, ZSTD_custo static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool) { unsigned u; + DEBUGLOG(3, "ZSTDMT_freeBufferPool (address:%08X)", (U32)bufPool); if (!bufPool) return; /* compatibility with free on NULL */ - for (u=0; utotalBuffers; u++) + for (u=0; utotalBuffers; u++) { + DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)bufPool->bTable[u].start); ZSTD_free(bufPool->bTable[u].start, bufPool->cMem); + } ZSTD_pthread_mutex_destroy(&bufPool->poolMutex); ZSTD_free(bufPool, bufPool->cMem); } @@ -485,12 +488,15 @@ static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx) unsigned jobID; DEBUGLOG(3, "ZSTDMT_releaseAllJobResources"); for (jobID=0; jobID <= mtctx->jobIDMask; jobID++) { + DEBUGLOG(4, "job%02u: release dst address %08X", jobID, (U32)mtctx->jobs[jobID].dstBuff.start); ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff); mtctx->jobs[jobID].dstBuff = g_nullBuffer; + DEBUGLOG(4, "job%02u: release src address %08X", jobID, (U32)mtctx->jobs[jobID].src.start); ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].src); mtctx->jobs[jobID].src = g_nullBuffer; } memset(mtctx->jobs, 0, (mtctx->jobIDMask+1)*sizeof(ZSTDMT_jobDescription)); + DEBUGLOG(4, "input: release address %08X", (U32)mtctx->inBuff.buffer.start); ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->inBuff.buffer); mtctx->inBuff.buffer = g_nullBuffer; mtctx->allJobsCompleted = 1; @@ -684,9 +690,8 @@ static size_t ZSTDMT_compress_advanced_internal( if (chunkID >= compressWithinDst) { /* chunk compressed into its own buffer, which must be released */ DEBUGLOG(5, "releasing buffer %u>=%u", chunkID, compressWithinDst); ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[chunkID].dstBuff); - } - mtctx->jobs[chunkID].dstBuff = g_nullBuffer; - } + } } + mtctx->jobs[chunkID].dstBuff = g_nullBuffer; dstPos += cSize ; } } /* for (chunkID=0; chunkID Date: Fri, 29 Sep 2017 15:54:09 -0700 Subject: [PATCH 222/248] decode more data before triggering error fixes #874 : when a frame is not properly terminated by a "last block" signal, zstd -d used to detect it immediately and error out. This version will decode and flush the last block, and only then issue an error. --- programs/fileio.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 9c5e2c40b..ab1644eb9 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1213,14 +1213,18 @@ unsigned long long FIO_decompressZstdFrame(dRess_t* ress, U64 frameSize = 0; U32 storedSkips = 0; + size_t const srcFileLength = strlen(srcFileName); + if (srcFileLength>20) srcFileName += srcFileLength-20; /* display last 20 characters only */ + ZSTD_resetDStream(ress->dctx); - if (strlen(srcFileName)>20) srcFileName += strlen(srcFileName)-20; /* display last 20 characters */ /* Header loading : ensures ZSTD_getFrameHeader() will succeed */ - { size_t const toRead = ZSTD_FRAMEHEADERSIZE_MAX; - if (ress->srcBufferLoaded < toRead) - ress->srcBufferLoaded += fread(((char*)ress->srcBuffer) + ress->srcBufferLoaded, 1, toRead - ress->srcBufferLoaded, finput); - } + { size_t const toDecode = ZSTD_FRAMEHEADERSIZE_MAX; + if (ress->srcBufferLoaded < toDecode) { + size_t const toRead = toDecode - ress->srcBufferLoaded; + void* const startPosition = (char*)ress->srcBuffer + ress->srcBufferLoaded; + ress->srcBufferLoaded += fread(startPosition, 1, toRead, finput); + } } /* Main decompression Loop */ while (1) { @@ -1253,14 +1257,17 @@ unsigned long long FIO_decompressZstdFrame(dRess_t* ress, } /* Fill input buffer */ - { size_t const toRead = MIN(readSizeHint, ress->srcBufferSize); /* support large skippable frames */ - if (ress->srcBufferLoaded < toRead) - ress->srcBufferLoaded += fread((char*)ress->srcBuffer + ress->srcBufferLoaded, - 1, toRead - ress->srcBufferLoaded, finput); - if (ress->srcBufferLoaded < toRead) { - DISPLAYLEVEL(1, "%s : Read error (39) : premature end \n", - srcFileName); - return FIO_ERROR_FRAME_DECODING; + { size_t const toDecode = MIN(readSizeHint, ress->srcBufferSize); /* support large skippable frames */ + if (ress->srcBufferLoaded < toDecode) { + size_t const toRead = toDecode - ress->srcBufferLoaded; /* > 0 */ + void* const startPosition = (char*)ress->srcBuffer + ress->srcBufferLoaded; + size_t const readSize = fread(startPosition, 1, toRead, finput); + if (readSize==0) { + DISPLAYLEVEL(1, "%s : Read error (39) : premature end \n", + srcFileName); + return FIO_ERROR_FRAME_DECODING; + } + ress->srcBufferLoaded += readSize; } } } FIO_fwriteSparseEnd(ress->dstFile, storedSkips); From 1416bc0f07b266e4c682f44968af1745dcce064c Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 29 Sep 2017 16:27:47 -0700 Subject: [PATCH 223/248] erase existence of a buffer when it's sent out of the pool In some complex scenario, the buffer would be freed because it's too large, another buffer would be allocated, but fail, trigger an error, and the general buffer pool would then be freed, where the definition of the already freed buffer would be found (beyond total index, but still), and freed again, resulting in double-free error. --- lib/compress/zstdmt_compress.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 03871421c..2d4fe2573 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -155,6 +155,7 @@ static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool) if (bufPool->nbBuffers) { /* try to use an existing buffer */ buffer_t const buf = bufPool->bTable[--(bufPool->nbBuffers)]; size_t const availBufferSize = buf.size; + bufPool->bTable[bufPool->nbBuffers] = g_nullBuffer; if ((availBufferSize >= bSize) & (availBufferSize <= 10*bSize)) { /* large enough, but not too much */ ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); From db1668a43b14df7159400d552e34d20627ba3218 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 29 Sep 2017 18:05:18 -0700 Subject: [PATCH 224/248] fix : srcSize written in frame header when multiple files compressed This information used to be disabled when nbFiles>1. It was badly initialized later in the code, resulting in an error. --- lib/compress/zstd_compress.c | 10 ++++++---- programs/fileio.c | 15 +++++++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 4c2254abe..9553ea9cd 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -822,11 +822,13 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, ZSTD_compResetPolicy_e const crp, ZSTD_buffered_policy_e const zbuff) { + DEBUGLOG(4, "ZSTD_resetCCtx_internal"); assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + DEBUGLOG(4, "pledgedSrcSize: %u", (U32)pledgedSrcSize); if (crp == ZSTDcrp_continue) { if (ZSTD_equivalentParams(params, zc->appliedParams)) { - DEBUGLOG(5, "ZSTD_equivalentParams()==1"); + DEBUGLOG(4, "ZSTD_equivalentParams()==1"); assert(!(params.ldmParams.enableLdm && params.ldmParams.hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET)); zc->entropy->hufCTable_repeatMode = HUF_repeat_none; @@ -2011,8 +2013,6 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, ZSTD_buffered_policy_e zbuff) { DEBUGLOG(4, "ZSTD_compressBegin_internal"); - DEBUGLOG(4, "dict ? %s", dict ? "dict" : (cdict ? "cdict" : "none")); - DEBUGLOG(4, "dictMode : %u", (U32)dictMode); /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ @@ -2485,7 +2485,7 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) ZSTD_CCtx_params params = zcs->requestedParams; params.fParams.contentSizeFlag = (pledgedSrcSize > 0); params.cParams = ZSTD_getCParamsFromCCtxParams(params, pledgedSrcSize, 0); - DEBUGLOG(5, "ZSTD_resetCStream"); + DEBUGLOG(4, "ZSTD_resetCStream"); return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, zcs->cdict, params, pledgedSrcSize); } @@ -2497,6 +2497,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, const void* dict, size_t dictSize, const ZSTD_CDict* cdict, ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) { + DEBUGLOG(4, "ZSTD_initCStream_internal"); assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ @@ -2768,6 +2769,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ + DEBUGLOG(4, "ZSTD_compress_generic : transparent init stage"); #ifdef ZSTD_MULTITHREAD if (params.nbThreads > 1) { diff --git a/programs/fileio.c b/programs/fileio.c index 9c5e2c40b..76726b475 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -757,6 +757,7 @@ static int FIO_compressFilename_internal(cRess_t ress, U64 readsize = 0; U64 compressedfilesize = 0; U64 const fileSize = UTIL_getFileSize(srcFileName); + DISPLAYLEVEL(5, "%s: %u bytes \n", srcFileName, (U32)fileSize); switch (g_compressionType) { case FIO_zstdCompression: @@ -796,7 +797,7 @@ static int FIO_compressFilename_internal(cRess_t ress, /* init */ #ifdef ZSTD_NEWAPI - /* nothing, reset is implied */ + CHECK( ZSTD_resetCStream(ress.cctx, fileSize) ); /* to pass fileSize */ #elif defined(ZSTD_MULTITHREAD) CHECK( ZSTDMT_resetCStream(ress.cctx, fileSize) ); #else @@ -849,10 +850,10 @@ static int FIO_compressFilename_internal(cRess_t ress, /* End of Frame */ { size_t result = 1; - while (result!=0) { /* note : is there any possibility of endless loop ? */ + while (result != 0) { ZSTD_outBuffer outBuff = { ress.dstBuffer, ress.dstBufferSize, 0 }; #ifdef ZSTD_NEWAPI - ZSTD_inBuffer inBuff = { NULL, 0, 0}; + ZSTD_inBuffer inBuff = { NULL, 0, 0 }; result = ZSTD_compress_generic(ress.cctx, &outBuff, &inBuff, ZSTD_e_end); #elif defined(ZSTD_MULTITHREAD) @@ -863,8 +864,10 @@ static int FIO_compressFilename_internal(cRess_t ress, if (ZSTD_isError(result)) EXM_THROW(26, "Compression error during frame end : %s", ZSTD_getErrorName(result)); - { size_t const sizeCheck = fwrite(ress.dstBuffer, 1, outBuff.pos, dstFile); - if (sizeCheck!=outBuff.pos) EXM_THROW(27, "Write error : cannot write frame end into %s", dstFileName); } + { size_t const sizeCheck = fwrite(ress.dstBuffer, 1, outBuff.pos, dstFile); + if (sizeCheck!=outBuff.pos) + EXM_THROW(27, "Write error : cannot write frame end into %s", dstFileName); + } compressedfilesize += outBuff.pos; } } @@ -974,7 +977,7 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile char* dstFileName = (char*)malloc(FNSPACE); size_t const suffixSize = suffix ? strlen(suffix) : 0; U64 const srcSize = (nbFiles != 1) ? 0 : UTIL_getFileSize(inFileNamesTable[0]) ; - int const isRegularFile = (nbFiles > 1) ? 0 : UTIL_isRegularFile(inFileNamesTable[0]); /* won't write frame content size when nbFiles > 1 */ + int const isRegularFile = (nbFiles > 1) ? 1 : UTIL_isRegularFile(inFileNamesTable[0]); /* if nbFiles > 1, it's not stdin */ cRess_t ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, isRegularFile, comprParams); /* init */ From fbd5ab70272095255948255368ac4f2f64aca780 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 29 Sep 2017 19:40:27 -0700 Subject: [PATCH 225/248] minor fix : no longer use fake srcSize during resource creation srcSize is read and provided at each file, not at resource creation. This used to be useful with older API, because it could not re-adapt parameters between sessions. At some point, it will be better to remove the old code, and only keep the new_api. It works fine by now. --- lib/compress/zstd_compress.c | 12 ++++++------ programs/fileio.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 9553ea9cd..6f369eba3 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -512,7 +512,7 @@ size_t ZSTD_CCtx_setParametersUsingCCtxParams( ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) { - DEBUGLOG(5, " setting pledgedSrcSize to %u", (U32)pledgedSrcSize); + DEBUGLOG(4, " setting pledgedSrcSize to %u", (U32)pledgedSrcSize); if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; return 0; @@ -524,7 +524,7 @@ size_t ZSTD_CCtx_loadDictionary_advanced( { if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */ - DEBUGLOG(5, "load dictionary of size %u", (U32)dictSize); + DEBUGLOG(4, "load dictionary of size %u", (U32)dictSize); ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */ if (dict==NULL || dictSize==0) { /* no dictionary mode */ cctx->cdictLocal = NULL; @@ -792,13 +792,13 @@ static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1, static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize) { U32 const end = (U32)(cctx->nextSrc - cctx->base); - DEBUGLOG(5, "continue mode"); + DEBUGLOG(4, "continue mode"); cctx->appliedParams = params; cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; cctx->consumedSrcSize = 0; if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) cctx->appliedParams.fParams.contentSizeFlag = 0; - DEBUGLOG(5, "pledged content size : %u ; flag : %u", + DEBUGLOG(4, "pledged content size : %u ; flag : %u", (U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag); cctx->lowLimit = end; cctx->dictLimit = end; @@ -2124,9 +2124,9 @@ size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize); if (ZSTD_isError(endResult)) return endResult; if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */ - DEBUGLOG(5, "end of frame : controlling src size"); + DEBUGLOG(4, "end of frame : controlling src size"); if (cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1) { - DEBUGLOG(5, "error : pledgedSrcSize = %u, while realSrcSize = %u", + DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize = %u", (U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize); return ERROR(srcSize_wrong); } } diff --git a/programs/fileio.c b/programs/fileio.c index 76726b475..6dc43de81 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -423,7 +423,7 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel, CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_contentSizeFlag, srcIsRegularFile) ); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_dictIDFlag, g_dictIDFlag) ); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_checksumFlag, g_checksumFlag) ); - CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, srcSize) ); + (void)srcSize; /* compression level */ CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionLevel, cLevel) ); /* long distance matching */ From 8afb151c9b0ddb102cee7637b22552fec1d6acb0 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 29 Sep 2017 22:14:37 -0700 Subject: [PATCH 226/248] cli: fixed wrong initialization in MT mode It's not good to mix old and new API ZSTD_resetCStream() doesn't just set pledgedSrcSize : it also sets the CCtx for a single thread compression. Problem is, when 2+ threads are defined in cctx->requestedParams, ZSTD_compress_generic() will want to start MT compression, since initialization is supposed to have already happened (thanks to ZSTD_resetCStream()) except that the underlying ZSTDMT_CCtx* object is not created, resulting in a segfault. This is an invalid construction (correct one is to use ZSTD_CCtx_setPledgedSrcSize()). I haven't found a nice way to mitigate this impact if someone makes the same mistake. At some point, removing the old API to keep only the new API within fileio.c will limit these risks. --- lib/compress/zstd_compress.c | 3 ++- programs/fileio.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 6f369eba3..7fccc180f 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -2756,6 +2756,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, ZSTD_inBuffer* input, ZSTD_EndDirective endOp) { + DEBUGLOG(5, "ZSTD_compress_generic"); /* check conditions */ if (output->pos > output->size) return ERROR(GENERIC); if (input->pos > input->size) return ERROR(GENERIC); @@ -2798,7 +2799,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, #ifdef ZSTD_MULTITHREAD if (cctx->appliedParams.nbThreads > 1) { size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); - DEBUGLOG(5, "ZSTDMT_compressStream_generic : %u", (U32)flushMin); + DEBUGLOG(5, "ZSTDMT_compressStream_generic result : %u", (U32)flushMin); if ( ZSTD_isError(flushMin) || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */ ZSTD_startNewCompression(cctx); diff --git a/programs/fileio.c b/programs/fileio.c index 6dc43de81..1319a5753 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -446,6 +446,7 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel, CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_targetLength, comprParams->targetLength) ); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionStrategy, (U32)comprParams->strategy) ); /* multi-threading */ + DISPLAYLEVEL(5,"set nb threads = %u \n", g_nbThreads); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nbThreads, g_nbThreads) ); /* dictionary */ CHECK( ZSTD_CCtx_loadDictionary(ress.cctx, dictBuffer, dictBuffSize) ); @@ -797,7 +798,8 @@ static int FIO_compressFilename_internal(cRess_t ress, /* init */ #ifdef ZSTD_NEWAPI - CHECK( ZSTD_resetCStream(ress.cctx, fileSize) ); /* to pass fileSize */ + if (fileSize!=0) /* if stdin, fileSize==0, but is effectively unknown */ + ZSTD_CCtx_setPledgedSrcSize(ress.cctx, fileSize); #elif defined(ZSTD_MULTITHREAD) CHECK( ZSTDMT_resetCStream(ress.cctx, fileSize) ); #else From 5b10345b263df7cf5aa078c3a084b3254a72326e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 29 Sep 2017 23:17:41 -0700 Subject: [PATCH 227/248] added ZSTD_COMPRESSBOUND() as a macro ZSTD_compressBound() works fine, but is only useful for dynamic allocation. For static allocation, only a macro can provide the amount during compilation time. --- lib/compress/zstd_compress.c | 4 +--- lib/zstd.h | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 4c2254abe..d234903b5 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -38,9 +38,7 @@ * Helper functions ***************************************/ size_t ZSTD_compressBound(size_t srcSize) { - size_t const lowLimit = 256 KB; - size_t const margin = (srcSize < lowLimit) ? (lowLimit-srcSize) >> 12 : 0; /* from 64 to 0 */ - return srcSize + (srcSize >> 8) + margin; + return ZSTD_COMPRESSBOUND(srcSize); } diff --git a/lib/zstd.h b/lib/zstd.h index 02241fd3f..5f3c0585f 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -131,10 +131,11 @@ ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t /*====== Helper functions ======*/ -ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */ +#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>9) + (((srcSize) < 128 KB) ? ((128 KB - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case scenario */ ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */ +ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */ /*************************************** From ee1ed78fcb3d53182c944940e16e697c94087a8b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 30 Sep 2017 11:08:50 -0700 Subject: [PATCH 228/248] fix proper naming on FSE_createCTable() arguments in fse.h --- lib/common/fse.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common/fse.h b/lib/common/fse.h index 1c44f8375..afd780196 100644 --- a/lib/common/fse.h +++ b/lib/common/fse.h @@ -184,7 +184,7 @@ FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize, const sh /*! Constructor and Destructor of FSE_CTable. Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */ typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */ -FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned tableLog, unsigned maxSymbolValue); +FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog); FSE_PUBLIC_API void FSE_freeCTable (FSE_CTable* ct); /*! FSE_buildCTable(): From c5d6dde502e4e30c7de4476e82b459361fe2f486 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Sat, 30 Sep 2017 14:17:32 -0700 Subject: [PATCH 229/248] Don't `size -= 1` in ZSTD_adjustCParams() The window size could end up too small if the source size is 2^n + 1. Credit to OSS-Fuzz --- lib/compress/zstd_compress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 4c2254abe..51cdeaf03 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -651,7 +651,7 @@ ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameter if (dictSize && (srcSize+1<2) /* srcSize unknown */ ) srcSize = minSrcSize; /* presumed small when there is a dictionary */ - else + else if (srcSize == 0) srcSize -= 1; /* unknown 0 => -1ULL : presumed large */ /* resize windowLog if input is small enough, to use less memory */ From dc404119e5377ce18e49bedeeab3f0ff8b815d87 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 30 Sep 2017 15:02:40 -0700 Subject: [PATCH 230/248] ZSTD_adjustCParams_internal : minor optimization --- lib/compress/zstd_compress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 51cdeaf03..2511ab29e 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -652,7 +652,7 @@ ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameter if (dictSize && (srcSize+1<2) /* srcSize unknown */ ) srcSize = minSrcSize; /* presumed small when there is a dictionary */ else if (srcSize == 0) - srcSize -= 1; /* unknown 0 => -1ULL : presumed large */ + srcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* 0 == unknown : presumed large */ /* resize windowLog if input is small enough, to use less memory */ if ( (srcSize < maxWindowResize) From 76ac0b2d999b0d0d47a2ef3078a2d8cf4dea1080 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 30 Sep 2017 15:34:44 -0700 Subject: [PATCH 231/248] macro compatible with scenario where windowSize = 1024 (minimum) --- lib/zstd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/zstd.h b/lib/zstd.h index 5f3c0585f..02491ed40 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -131,7 +131,7 @@ ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t /*====== Helper functions ======*/ -#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>9) + (((srcSize) < 128 KB) ? ((128 KB - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) +#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < 128 KB) ? ((128 KB - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case scenario */ ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */ From 5db19b8685e4287de4a3231f31c4bf0e649783db Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 1 Oct 2017 11:32:38 -0700 Subject: [PATCH 232/248] added comment on ZSTD_COMPRESSBOUND() as requested by @terrelln --- lib/zstd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/zstd.h b/lib/zstd.h index 02491ed40..4e225bb5e 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -131,7 +131,7 @@ ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t /*====== Helper functions ======*/ -#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < 128 KB) ? ((128 KB - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) +#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < 128 KB) ? ((128 KB - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */ ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case scenario */ ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */ From 00fc1ba8ddcfd9a0c1b9b32bf6da3978901c723e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 1 Oct 2017 12:10:26 -0700 Subject: [PATCH 233/248] cli: add Ctrl-C support, requested by @mike155 in #854 Now, pressing Ctrl-C during compression or decompression will erase operation artefact (unfinished destination file) before leaving execution. --- programs/fileio.c | 36 ++++++++++++++++++++++++++++++++++++ programs/zstdcli.c | 1 + 2 files changed, 37 insertions(+) diff --git a/programs/fileio.c b/programs/fileio.c index 507cc5c60..83934beef 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -140,6 +140,21 @@ static clock_t g_time = 0; } } +/*-************************************ +* Signal (Ctrl-C trapping) +**************************************/ +#include + +const char* g_artefact = NULL; +void INThandler(int sig) +{ + signal(sig, SIG_IGN); + remove(g_artefact); + DISPLAY("\n"); + exit(1); +} + + /* ************************************************************ * Avoid fseek()'s 2GiB barrier with MSVC, MacOS, *BSD, MinGW ***************************************************************/ @@ -929,6 +944,14 @@ static int FIO_compressFilename_dstFile(cRess_t ress, ress.dstFile = FIO_openDstFile(dstFileName); if (ress.dstFile==NULL) return 1; /* could not open dstFileName */ + if (UTIL_isRegularFile(dstFileName)) { + g_artefact = dstFileName; + signal(SIGINT, INThandler); + } else { + g_artefact = NULL; + } + + if (strcmp (srcFileName, stdinmark) && UTIL_getFileStat(srcFileName, &statbuf)) stat_result = 1; result = FIO_compressFilename_srcFile(ress, dstFileName, srcFileName, compressionLevel); @@ -943,6 +966,9 @@ static int FIO_compressFilename_dstFile(cRess_t ress, } else if (strcmp (dstFileName, stdoutmark) && stat_result) UTIL_setFileStat(dstFileName, &statbuf); + + signal(SIGINT, SIG_DFL); + return result; } @@ -1629,6 +1655,13 @@ static int FIO_decompressDstFile(dRess_t ress, ress.dstFile = FIO_openDstFile(dstFileName); if (ress.dstFile==0) return 1; + if (UTIL_isRegularFile(dstFileName)) { + g_artefact = dstFileName; + signal(SIGINT, INThandler); + } else { + g_artefact = NULL; + } + if ( strcmp(srcFileName, stdinmark) && UTIL_getFileStat(srcFileName, &statbuf) ) stat_result = 1; @@ -1649,6 +1682,9 @@ static int FIO_decompressDstFile(dRess_t ress, && stat_result ) /* file permissions correctly extracted from src */ UTIL_setFileStat(dstFileName, &statbuf); /* transfer file permissions from src into dst */ } + + signal(SIGINT, SIG_DFL); + return result; } diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 801dc448b..3f8367341 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -406,6 +406,7 @@ int main(int argCount, const char* argv[]) int cover = 1; #endif + /* init */ (void)recursive; (void)cLevelLast; /* not used when ZSTD_NOBENCH set */ (void)dictCLevel; (void)dictSelect; (void)dictID; (void)maxDictSize; /* not used when ZSTD_NODICT set */ From bd18095edcd3ae03201201de406a752a5395149b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 1 Oct 2017 15:32:48 -0700 Subject: [PATCH 234/248] blindfix for Visual : minor casting issue should not happen since SIGIGN is provided by , so it should work "ouf of the box" --- programs/fileio.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 83934beef..e22d2bac8 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -145,13 +145,15 @@ static clock_t g_time = 0; **************************************/ #include +typedef void (*signalHandler_f) (int); const char* g_artefact = NULL; void INThandler(int sig) { - signal(sig, SIG_IGN); - remove(g_artefact); + assert(sig==SIGINT); + signal(sig, (signalHandler_f)SIG_IGN); /* cast required to circumvent a bug in Visual Studio 2008 */ + if (g_artefact) remove(g_artefact); DISPLAY("\n"); - exit(1); + exit(2); } From 82bc200f82eceb2b8bfaddacd5f0611db02d351b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 2 Oct 2017 00:02:24 -0700 Subject: [PATCH 235/248] conditionnally removed invocation that generates a buggy warning with Visual Studio 2008 --- programs/fileio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index e22d2bac8..6bf414e5a 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -145,12 +145,13 @@ static clock_t g_time = 0; **************************************/ #include -typedef void (*signalHandler_f) (int); const char* g_artefact = NULL; void INThandler(int sig) { assert(sig==SIGINT); - signal(sig, (signalHandler_f)SIG_IGN); /* cast required to circumvent a bug in Visual Studio 2008 */ +#if !(defined(_MSC_VER) && (_MSC_VER <= 1500 /* visual studio 2008 */)) + signal(sig, SIG_IGN); /* this invocation generates a buggy warning in Visual Studio 2008 */ +#endif if (g_artefact) remove(g_artefact); DISPLAY("\n"); exit(2); From 6e7ba3df2fc7d139b76544038691047bdddb8151 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 2 Oct 2017 00:19:47 -0700 Subject: [PATCH 236/248] added (void)sig to avoid compilers complaining that sig is not used. --- programs/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/fileio.c b/programs/fileio.c index 6bf414e5a..cd78bbc04 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -148,7 +148,7 @@ static clock_t g_time = 0; const char* g_artefact = NULL; void INThandler(int sig) { - assert(sig==SIGINT); + assert(sig==SIGINT); (void)sig; #if !(defined(_MSC_VER) && (_MSC_VER <= 1500 /* visual studio 2008 */)) signal(sig, SIG_IGN); /* this invocation generates a buggy warning in Visual Studio 2008 */ #endif From ed7ae4c9bd1549b866cb96b785e8f76caa69c6a7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 2 Oct 2017 00:45:28 -0700 Subject: [PATCH 237/248] The issue also impacts Visual Studio 2010 --- programs/fileio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index cd78bbc04..2ab017a52 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -149,8 +149,8 @@ const char* g_artefact = NULL; void INThandler(int sig) { assert(sig==SIGINT); (void)sig; -#if !(defined(_MSC_VER) && (_MSC_VER <= 1500 /* visual studio 2008 */)) - signal(sig, SIG_IGN); /* this invocation generates a buggy warning in Visual Studio 2008 */ +#if !(defined(_MSC_VER) && (_MSC_VER <= 1600 /* visual studio 2010 */)) + signal(sig, SIG_IGN); /* this invocation generates a buggy warning in Visual Studio up to 2010 */ #endif if (g_artefact) remove(g_artefact); DISPLAY("\n"); From 51d82d55165299a1b1411f4cbe7469bac13a7e7c Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 2 Oct 2017 01:12:40 -0700 Subject: [PATCH 238/248] same error in Visual Studio 2012 ... --- programs/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/fileio.c b/programs/fileio.c index 2ab017a52..bd51972a8 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -149,7 +149,7 @@ const char* g_artefact = NULL; void INThandler(int sig) { assert(sig==SIGINT); (void)sig; -#if !(defined(_MSC_VER) && (_MSC_VER <= 1600 /* visual studio 2010 */)) +#if !(defined(_MSC_VER) && (_MSC_VER < 1700 /* < visual studio 2012 */)) signal(sig, SIG_IGN); /* this invocation generates a buggy warning in Visual Studio up to 2010 */ #endif if (g_artefact) remove(g_artefact); From fe5444bc66b7a0aee09de6724e01f9be55daa8cc Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 2 Oct 2017 02:02:16 -0700 Subject: [PATCH 239/248] removed the statement for all versions of Visual Studio --- programs/fileio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index bd51972a8..dafc12468 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -149,8 +149,8 @@ const char* g_artefact = NULL; void INThandler(int sig) { assert(sig==SIGINT); (void)sig; -#if !(defined(_MSC_VER) && (_MSC_VER < 1700 /* < visual studio 2012 */)) - signal(sig, SIG_IGN); /* this invocation generates a buggy warning in Visual Studio up to 2010 */ +#if !defined(_MSC_VER) + signal(sig, SIG_IGN); /* this invocation generates a buggy warning in Visual Studio */ #endif if (g_artefact) remove(g_artefact); DISPLAY("\n"); From 0d58aaf6f066297e546e3334af7ca6c9fa6e363e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 2 Oct 2017 02:07:17 -0700 Subject: [PATCH 240/248] /contrib: fixed license header removed last reference to PATENTS file --- contrib/seekable_format/zstdseek_decompress.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contrib/seekable_format/zstdseek_decompress.c b/contrib/seekable_format/zstdseek_decompress.c index 4a8b4e568..d740e16be 100644 --- a/contrib/seekable_format/zstdseek_decompress.c +++ b/contrib/seekable_format/zstdseek_decompress.c @@ -2,9 +2,10 @@ * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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. */ /* ********************************************************* From 7f580f9ee8b19fd29bc07a247b2d438f970072e7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 2 Oct 2017 11:39:05 -0700 Subject: [PATCH 241/248] interruption handler and variable are static --- programs/fileio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index dafc12468..8d6ab35d0 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -145,8 +145,8 @@ static clock_t g_time = 0; **************************************/ #include -const char* g_artefact = NULL; -void INThandler(int sig) +static const char* g_artefact = NULL; +static void INThandler(int sig) { assert(sig==SIGINT); (void)sig; #if !defined(_MSC_VER) From 4946993f870357b9091c96804de4bd84df133230 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 2 Oct 2017 12:29:25 -0700 Subject: [PATCH 242/248] removed isRegularFile parameter no longer useful : size of src is determined for each file. --- programs/fileio.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 1319a5753..c30349ae5 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -382,7 +382,7 @@ typedef struct { } cRess_t; static cRess_t FIO_createCResources(const char* dictFileName, int cLevel, - U64 srcSize, int srcIsRegularFile, + U64 srcSize, ZSTD_compressionParameters* comprParams) { cRess_t ress; memset(&ress, 0, sizeof(ress)); @@ -420,7 +420,6 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel, #ifdef ZSTD_NEWAPI { /* frame parameters */ - CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_contentSizeFlag, srcIsRegularFile) ); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_dictIDFlag, g_dictIDFlag) ); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_checksumFlag, g_checksumFlag) ); (void)srcSize; @@ -453,7 +452,6 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel, } #elif defined(ZSTD_MULTITHREAD) { ZSTD_parameters params = ZSTD_getParams(cLevel, srcSize, dictBuffSize); - params.fParams.contentSizeFlag = srcIsRegularFile; params.fParams.checksumFlag = g_checksumFlag; params.fParams.noDictIDFlag = !g_dictIDFlag; if (comprParams->windowLog) params.cParams.windowLog = comprParams->windowLog; @@ -468,7 +466,6 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel, } #else { ZSTD_parameters params = ZSTD_getParams(cLevel, srcSize, dictBuffSize); - params.fParams.contentSizeFlag = srcIsRegularFile; params.fParams.checksumFlag = g_checksumFlag; params.fParams.noDictIDFlag = !g_dictIDFlag; if (comprParams->windowLog) params.cParams.windowLog = comprParams->windowLog; @@ -798,12 +795,12 @@ static int FIO_compressFilename_internal(cRess_t ress, /* init */ #ifdef ZSTD_NEWAPI - if (fileSize!=0) /* if stdin, fileSize==0, but is effectively unknown */ - ZSTD_CCtx_setPledgedSrcSize(ress.cctx, fileSize); + if (fileSize!=0) /* when src is stdin, fileSize==0, but is effectively unknown */ + ZSTD_CCtx_setPledgedSrcSize(ress.cctx, fileSize); /* note : fileSize==0 means "empty" */ #elif defined(ZSTD_MULTITHREAD) - CHECK( ZSTDMT_resetCStream(ress.cctx, fileSize) ); + CHECK( ZSTDMT_resetCStream(ress.cctx, fileSize) ); /* note : fileSize==0 means "unknown" */ #else - CHECK( ZSTD_resetCStream(ress.cctx, fileSize) ); + CHECK( ZSTD_resetCStream(ress.cctx, fileSize) ); /* note : fileSize==0 means "unknown" */ #endif /* Main compression loop */ @@ -863,9 +860,10 @@ static int FIO_compressFilename_internal(cRess_t ress, #else result = ZSTD_endStream(ress.cctx, &outBuff); #endif - if (ZSTD_isError(result)) + if (ZSTD_isError(result)) { EXM_THROW(26, "Compression error during frame end : %s", ZSTD_getErrorName(result)); + } { size_t const sizeCheck = fwrite(ress.dstBuffer, 1, outBuff.pos, dstFile); if (sizeCheck!=outBuff.pos) EXM_THROW(27, "Write error : cannot write frame end into %s", dstFileName); @@ -956,9 +954,8 @@ int FIO_compressFilename(const char* dstFileName, const char* srcFileName, { clock_t const start = clock(); U64 const srcSize = UTIL_getFileSize(srcFileName); - int const isRegularFile = UTIL_isRegularFile(srcFileName); - cRess_t const ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, isRegularFile, comprParams); + cRess_t const ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, comprParams); int const result = FIO_compressFilename_dstFile(ress, dstFileName, srcFileName, compressionLevel); double const seconds = (double)(clock() - start) / CLOCKS_PER_SEC; @@ -979,8 +976,7 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile char* dstFileName = (char*)malloc(FNSPACE); size_t const suffixSize = suffix ? strlen(suffix) : 0; U64 const srcSize = (nbFiles != 1) ? 0 : UTIL_getFileSize(inFileNamesTable[0]) ; - int const isRegularFile = (nbFiles > 1) ? 1 : UTIL_isRegularFile(inFileNamesTable[0]); /* if nbFiles > 1, it's not stdin */ - cRess_t ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, isRegularFile, comprParams); + cRess_t ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, comprParams); /* init */ if (dstFileName==NULL) From 86e83e926f1d8c03447865b340fc6126093eb517 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Mon, 2 Oct 2017 13:43:30 -0700 Subject: [PATCH 243/248] [libzstd] Set CLEVEL_CUSTOM correctly In `ZSTD_compressBegin_advanced()`, `ZSTD_parameters` are used to set the compression parameters, but the level didn't get set to `CLEVEL_CUSTOM`, so `ZSTD_compressBlock()` used the wrong parameters when checking the source size. --- lib/compress/zstd_compress.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 892912f2e..35aede3c4 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -240,6 +240,7 @@ static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( ZSTD_CCtx_params ret = cctxParams; ret.cParams = params.cParams; ret.fParams = params.fParams; + ret.compressionLevel = ZSTD_CLEVEL_CUSTOM; return ret; } From 7e00df4a496985880baee79d677a53573e9abaf7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 2 Oct 2017 16:27:25 -0700 Subject: [PATCH 244/248] bumped version number and updated NEWS in anticipation for release --- NEWS | 14 ++++++++++++-- lib/zstd.h | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index cddc8fc13..215c0a329 100644 --- a/NEWS +++ b/NEWS @@ -1,15 +1,25 @@ v1.3.2 new : long range mode, using --long command, by Stella Lau (@stellamplau) -license : changed /examples license to BSD + GPLv2 -license : fix a few header files to reflect new license (#825) +new : ability to generate and decode magicless frames (#591) +changed : maximum nb of threads reduced to 200, to avoid address space exhaustion in 32-bits mode fix : multi-threading compression works with custom allocators fix : ZSTD_sizeof_CStream() was over-evaluating memory usage fix : a rare compression bug when compression generates very large distances and bunch of other conditions (only possible at --ultra -22) fix : 32-bits build can now decode large offsets (levels 21+) +cli : added LZ4 frame support by default, by Felix Handte (@felixhandte) +cli : improved --list output cli : new : can split input file for dictionary training, using command -B# +cli : new : clean operation artefact on Ctrl-C interruption cli : fix : do not change /dev/null permissions when using command -t with root access, reported by @mike155 (#851) +cli : fix : write file size in header in multiple-files mode +api : added macro ZSTD_COMPRESSBOUND() for static allocation +api : experimental : new advanced decompression API +api : fix : sizeof_CCtx() used to over-estimate build: fix : no-multithread variant compiles without pool.c dependency, reported by Mitchell Blank Jr (@mitchblank) (#819) build: better compatibility with reproducible builds, by Bernhard M. Wiedemann (@bmwiedemann) (#818) +example : added streaming_memory_usage +license : changed /examples license to BSD + GPLv2 +license : fix a few header files to reflect new license (#825) v1.3.1 New license : BSD + GPLv2 diff --git a/lib/zstd.h b/lib/zstd.h index 02241fd3f..12f41e631 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -59,7 +59,7 @@ extern "C" { /*------ Version ------*/ #define ZSTD_VERSION_MAJOR 1 #define ZSTD_VERSION_MINOR 3 -#define ZSTD_VERSION_RELEASE 1 +#define ZSTD_VERSION_RELEASE 2 #define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< useful to check dll version */ From 67478f4cb0f582d83c8846bd3b84ed824bc08c6f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 2 Oct 2017 17:28:57 -0700 Subject: [PATCH 245/248] fixed minor conversion warnings for printf in debug mode --- lib/compress/zstdmt_compress.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 8af527f09..7831cd3bd 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -115,10 +115,10 @@ static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbThreads, ZSTD_custo static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool) { unsigned u; - DEBUGLOG(3, "ZSTDMT_freeBufferPool (address:%08X)", (U32)bufPool); + DEBUGLOG(3, "ZSTDMT_freeBufferPool (address:%08X)", (U32)(size_t)bufPool); if (!bufPool) return; /* compatibility with free on NULL */ for (u=0; utotalBuffers; u++) { - DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)bufPool->bTable[u].start); + DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)(size_t)bufPool->bTable[u].start); ZSTD_free(bufPool->bTable[u].start, bufPool->cMem); } ZSTD_pthread_mutex_destroy(&bufPool->poolMutex); @@ -489,15 +489,15 @@ static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx) unsigned jobID; DEBUGLOG(3, "ZSTDMT_releaseAllJobResources"); for (jobID=0; jobID <= mtctx->jobIDMask; jobID++) { - DEBUGLOG(4, "job%02u: release dst address %08X", jobID, (U32)mtctx->jobs[jobID].dstBuff.start); + DEBUGLOG(4, "job%02u: release dst address %08X", jobID, (U32)(size_t)mtctx->jobs[jobID].dstBuff.start); ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff); mtctx->jobs[jobID].dstBuff = g_nullBuffer; - DEBUGLOG(4, "job%02u: release src address %08X", jobID, (U32)mtctx->jobs[jobID].src.start); + DEBUGLOG(4, "job%02u: release src address %08X", jobID, (U32)(size_t)mtctx->jobs[jobID].src.start); ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].src); mtctx->jobs[jobID].src = g_nullBuffer; } memset(mtctx->jobs, 0, (mtctx->jobIDMask+1)*sizeof(ZSTDMT_jobDescription)); - DEBUGLOG(4, "input: release address %08X", (U32)mtctx->inBuff.buffer.start); + DEBUGLOG(4, "input: release address %08X", (U32)(size_t)mtctx->inBuff.buffer.start); ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->inBuff.buffer); mtctx->inBuff.buffer = g_nullBuffer; mtctx->allJobsCompleted = 1; From a86a7097ec70113a061f77526e9803a82651a60f Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 3 Oct 2017 13:22:13 -0700 Subject: [PATCH 246/248] Ensure dictionary Huff table can encode any symbol * Ensure that the dictionary Huffman CTable has maxSymbolValue 255. * Fix a stack buffer overflow during compression dictionary loading. --- lib/common/huf.h | 2 +- lib/compress/huf_compress.c | 7 ++++--- lib/compress/zstd_compress.c | 4 +++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/common/huf.h b/lib/common/huf.h index 2b3015a84..522bf9b6c 100644 --- a/lib/common/huf.h +++ b/lib/common/huf.h @@ -242,7 +242,7 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, /** HUF_readCTable() : * Loading a CTable saved with HUF_writeCTable() */ -size_t HUF_readCTable (HUF_CElt* CTable, unsigned maxSymbolValue, const void* src, size_t srcSize); +size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize); /* diff --git a/lib/compress/huf_compress.c b/lib/compress/huf_compress.c index 2a47c1820..5692d56e0 100644 --- a/lib/compress/huf_compress.c +++ b/lib/compress/huf_compress.c @@ -167,7 +167,7 @@ size_t HUF_writeCTable (void* dst, size_t maxDstSize, } -size_t HUF_readCTable (HUF_CElt* CTable, U32 maxSymbolValue, const void* src, size_t srcSize) +size_t HUF_readCTable (HUF_CElt* CTable, U32* maxSymbolValuePtr, const void* src, size_t srcSize) { BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; /* init not required, even though some static analyzer may complain */ U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */ @@ -179,7 +179,7 @@ size_t HUF_readCTable (HUF_CElt* CTable, U32 maxSymbolValue, const void* src, si /* check result */ if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); - if (nbSymbols > maxSymbolValue+1) return ERROR(maxSymbolValue_tooSmall); + if (nbSymbols > *maxSymbolValuePtr+1) return ERROR(maxSymbolValue_tooSmall); /* Prepare base value per rank */ { U32 n, nextRankStart = 0; @@ -208,9 +208,10 @@ size_t HUF_readCTable (HUF_CElt* CTable, U32 maxSymbolValue, const void* src, si min >>= 1; } } /* assign value within rank, symbol order */ - { U32 n; for (n=0; n<=maxSymbolValue; n++) CTable[n].val = valPerRank[CTable[n].nbBits]++; } + { U32 n; for (n=0; ndictID = cctx->appliedParams.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr); dictPtr += 4; - { size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)cctx->entropy->hufCTable, 255, dictPtr, dictEnd-dictPtr); + { unsigned maxSymbolValue = 255; + size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)cctx->entropy->hufCTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr); if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted); + if (maxSymbolValue < 255) return ERROR(dictionary_corrupted); dictPtr += hufHeaderSize; } From 6dd958eea203198482034a6de7993a392bc5c347 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 4 Oct 2017 12:23:23 -0700 Subject: [PATCH 247/248] [zstdcli] Add window size to verbose list ``` > zstd --list -v file1 file2 file3 *** zstd command line interface 64-bits v1.3.2, by Yann Collet *** Window Size: 512.00 KB (524288 B) Compressed Size: 0.02 KB (19 B) Check: XXH64 Window Size: 8192.00 KB (8388608 B) Compressed Size: 0.02 KB (19 B) Check: XXH64 Window Size: 512.00 KB (524288 B) Compressed Size: 0.01 KB (15 B) Check: None ``` --- programs/fileio.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 8c18cf24c..70158f930 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1780,11 +1780,12 @@ int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles ***************************************************************************/ typedef struct { + U64 decompressedSize; + U64 compressedSize; + U64 windowSize; int numActualFrames; int numSkippableFrames; - U64 decompressedSize; int decompUnavailable; - U64 compressedSize; int usesCheck; U32 nbFiles; } fileInfo_t; @@ -1829,12 +1830,19 @@ static int getFileInfo(fileInfo_t* info, const char* inFileName){ { U32 const magicNumber = MEM_readLE32(headerBuffer); /* Zstandard frame */ if (magicNumber == ZSTD_MAGICNUMBER) { + ZSTD_frameHeader header; U64 const frameContentSize = ZSTD_getFrameContentSize(headerBuffer, numBytesRead); if (frameContentSize == ZSTD_CONTENTSIZE_ERROR || frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN) { info->decompUnavailable = 1; } else { info->decompressedSize += frameContentSize; } + if (ZSTD_getFrameHeader(&header, headerBuffer, numBytesRead) != 0) { + DISPLAY("Error: could not decode frame header\n"); + detectError = 1; + break; + } + info->windowSize = header.windowSize; /* move to the end of the frame header */ { size_t const headerSize = ZSTD_frameHeaderSize(headerBuffer, numBytesRead); if (ZSTD_isError(headerSize)) { @@ -1921,6 +1929,7 @@ static int getFileInfo(fileInfo_t* info, const char* inFileName){ static void displayInfo(const char* inFileName, fileInfo_t* info, int displayLevel){ unsigned const unit = info->compressedSize < (1 MB) ? (1 KB) : (1 MB); const char* const unitStr = info->compressedSize < (1 MB) ? "KB" : "MB"; + double const windowSizeUnit = (double)info->windowSize / unit; double const compressedSizeUnit = (double)info->compressedSize / unit; double const decompressedSizeUnit = (double)info->decompressedSize / unit; double const ratio = (info->compressedSize == 0) ? 0 : ((double)info->decompressedSize)/info->compressedSize; @@ -1942,6 +1951,9 @@ static void displayInfo(const char* inFileName, fileInfo_t* info, int displayLev } else { DISPLAYOUT("# Zstandard Frames: %d\n", info->numActualFrames); DISPLAYOUT("# Skippable Frames: %d\n", info->numSkippableFrames); + DISPLAYOUT("Window Size: %.2f %2s (%llu B)\n", + windowSizeUnit, unitStr, + (unsigned long long)info->windowSize); DISPLAYOUT("Compressed Size: %.2f %2s (%llu B)\n", compressedSizeUnit, unitStr, (unsigned long long)info->compressedSize); @@ -1999,7 +2011,9 @@ int FIO_listMultipleFiles(unsigned numFiles, const char** filenameTable, int dis DISPLAYOUT("No files given\n"); return 0; } - DISPLAYOUT("Frames Skips Compressed Uncompressed Ratio Check Filename\n"); + if (displayLevel <= 2) { + DISPLAYOUT("Frames Skips Compressed Uncompressed Ratio Check Filename\n"); + } { int error = 0; unsigned u; fileInfo_t total; @@ -2008,7 +2022,7 @@ int FIO_listMultipleFiles(unsigned numFiles, const char** filenameTable, int dis for (u=0; u 1) { + if (numFiles > 1 && displayLevel <= 2) { unsigned const unit = total.compressedSize < (1 MB) ? (1 KB) : (1 MB); const char* const unitStr = total.compressedSize < (1 MB) ? "KB" : "MB"; double const compressedSizeUnit = (double)total.compressedSize / unit; From 4252621e26110b1f35cef11962a7aa6b41618f18 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 5 Oct 2017 20:21:59 -0700 Subject: [PATCH 248/248] playtests: do not use cat on large files some target have limitation making cat incompatible with large files (namely debian hurd-i386) --- tests/playTests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/playTests.sh b/tests/playTests.sh index b588949c0..bc021648c 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -43,7 +43,7 @@ fileRoundTripTest() { rm -f tmp.zstd tmp.md5.1 tmp.md5.2 $ECHO "fileRoundTripTest: ./datagen $1 $local_p > tmp && $ZSTD -v$local_c -c tmp | $ZSTD -d$local_d" ./datagen $1 $local_p > tmp - cat tmp | $MD5SUM > tmp.md5.1 + < tmp $MD5SUM > tmp.md5.1 $ZSTD --ultra -v$local_c -c tmp | $ZSTD -d$local_d | $MD5SUM > tmp.md5.2 $DIFF -q tmp.md5.1 tmp.md5.2 }