3485 lines · 127.0 KB · C
RawDownload
/** * 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 * 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"). */ /*-**************************************  Dependencies***************************************/#include "fse.h"#include "huf.h"#include "mem.h"#include "zstd_internal.h" /* includes zstd.h */#include <linux/kernel.h>#include <linux/module.h>#include <linux/string.h> /* memset */ /*-**************************************  Constants***************************************/static const U32 g_searchStrength = 8; /* control skip over incompressible data */#define HASH_READ_SIZE 8typedef enum { ZSTDcs_created = 0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e; /*-**************************************  Helper functions***************************************/size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; } /*-**************************************  Sequence storage***************************************/static void ZSTD_resetSeqStore(seqStore_t *ssPtr){	ssPtr->lit = ssPtr->litStart;	ssPtr->sequences = ssPtr->sequencesStart;	ssPtr->longLengthID = 0;} /*-**************************************  Context memory management***************************************/struct ZSTD_CCtx_s {	const BYTE *nextSrc;  /* next block here to continue on curr 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 */	U32 forceWindow;      /* force back-references to respect limit of 1<<wLog, even for dictionary */	U32 forceRawDict;     /* Force loading dictionary in "content-only" mode (no header analysis) */	ZSTD_compressionStage_e stage;	U32 rep[ZSTD_REP_NUM];	U32 repToConfirm[ZSTD_REP_NUM];	U32 dictID;	ZSTD_parameters params;	void *workSpace;	size_t workSpaceSize;	size_t blockSize;	U64 frameContentSize;	struct xxh64_state xxhState;	ZSTD_customMem customMem; 	seqStore_t seqStore; /* sequences storage ptrs */	U32 *hashTable;	U32 *hashTable3;	U32 *chainTable;	HUF_CElt *hufTable;	U32 flagStaticTables;	HUF_repeat flagStaticHufTable;	FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];	FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];	FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];	unsigned tmpCounters[HUF_COMPRESS_WORKSPACE_SIZE_U32];}; size_t ZSTD_CCtxWorkspaceBound(ZSTD_compressionParameters cParams){	size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (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 tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);	size_t const optSpace =	    ((MaxML + 1) + (MaxLL + 1) + (MaxOff + 1) + (1 << Litbits)) * sizeof(U32) + (ZSTD_OPT_NUM + 1) * (sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));	size_t const workspaceSize = tableSpace + (256 * sizeof(U32)) /* huffTable */ + tokenSpace +				     (((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btopt2)) ? optSpace : 0); 	return ZSTD_ALIGN(sizeof(ZSTD_stack)) + ZSTD_ALIGN(sizeof(ZSTD_CCtx)) + ZSTD_ALIGN(workspaceSize);} static ZSTD_CCtx *ZSTD_createCCtx_advanced(ZSTD_customMem customMem){	ZSTD_CCtx *cctx;	if (!customMem.customAlloc || !customMem.customFree)		return NULL;	cctx = (ZSTD_CCtx *)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);	if (!cctx)		return NULL;	memset(cctx, 0, sizeof(ZSTD_CCtx));	cctx->customMem = customMem;	return cctx;} ZSTD_CCtx *ZSTD_initCCtx(void *workspace, size_t workspaceSize){	ZSTD_customMem const stackMem = ZSTD_initStack(workspace, workspaceSize);	ZSTD_CCtx *cctx = ZSTD_createCCtx_advanced(stackMem);	if (cctx) {		cctx->workSpace = ZSTD_stackAllocAll(cctx->customMem.opaque, &cctx->workSpaceSize);	}	return cctx;} size_t ZSTD_freeCCtx(ZSTD_CCtx *cctx){	if (cctx == NULL)		return 0; /* support free on NULL */	ZSTD_free(cctx->workSpace, cctx->customMem);	ZSTD_free(cctx, cctx->customMem);	return 0; /* reserved as a potential error code in the future */} const seqStore_t *ZSTD_getSeqStore(const ZSTD_CCtx *ctx) /* hidden interface */ { return &(ctx->seqStore); } static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx *cctx) { return cctx->params; } /** ZSTD_checkParams() :	ensure param values remain within authorized range.	@return : 0, or an error code if one value is beyond authorized range */size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams){#define CLAMPCHECK(val, min, max)                                       \	{                                                               \		if ((val < min) | (val > max))                          \			return ERROR(compressionParameter_unsupported); \	}	CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);	CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);	CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);	CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);	CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);	CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);	if ((U32)(cParams.strategy) > (U32)ZSTD_btopt2)		return ERROR(compressionParameter_unsupported);	return 0;} /** ZSTD_cycleLog() : *  condition for correct operation : hashLog > 1 */static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat){	U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);	return hashLog - btScale;} /** ZSTD_adjustCParams() :	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.	Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize){	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;		U64 const rSize = srcSize + dictSize + minSrcSize;		if (rSize < ((U64)1 << ZSTD_WINDOWLOG_MAX)) {			U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-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)			cPar.chainLog -= (cycleLog - cPar.windowLog);	} 	if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)		cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */ 	return cPar;} static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2){	return (param1.cParams.hashLog == param2.cParams.hashLog) & (param1.cParams.chainLog == param2.cParams.chainLog) &	       (param1.cParams.strategy == param2.cParams.strategy) & ((param1.cParams.searchLength == 3) == (param2.cParams.searchLength == 3));} /*! ZSTD_continueCCtx() :	reuse CCtx without reset (note : requires no dictionary) */static size_t ZSTD_continueCCtx(ZSTD_CCtx *cctx, ZSTD_parameters params, U64 frameContentSize){	U32 const end = (U32)(cctx->nextSrc - cctx->base);	cctx->params = params;	cctx->frameContentSize = frameContentSize;	cctx->lowLimit = end;	cctx->dictLimit = end;	cctx->nextToUpdate = end + 1;	cctx->stage = ZSTDcs_init;	cctx->dictID = 0;	cctx->loadedDictEnd = 0;	{		int i;		for (i = 0; i < ZSTD_REP_NUM; i++)			cctx->rep[i] = repStartValue[i];	}	cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */	xxh64_reset(&cctx->xxhState, 0);	return 0;} typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e; /*! ZSTD_resetCCtx_advanced() :	note : `params` must be validated */static size_t ZSTD_resetCCtx_advanced(ZSTD_CCtx *zc, ZSTD_parameters params, U64 frameContentSize, ZSTD_compResetPolicy_e const crp){	if (crp == ZSTDcrp_continue)		if (ZSTD_equivalentParams(params, zc->params)) {			zc->flagStaticTables = 0;			zc->flagStaticHufTable = HUF_repeat_none;			return ZSTD_continueCCtx(zc, params, frameContentSize);		} 	{		size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);		U32 const divider = (params.cParams.searchLength == 3) ? 3 : 4;		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);		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);		size_t const h3Size = ((size_t)1) << hashLog3;		size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);		void *ptr; 		/* Check if workSpace is large enough, alloc a new one if needed */		{			size_t const optSpace = ((MaxML + 1) + (MaxLL + 1) + (MaxOff + 1) + (1 << Litbits)) * sizeof(U32) +						(ZSTD_OPT_NUM + 1) * (sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));			size_t const neededSpace = tableSpace + (256 * sizeof(U32)) /* huffTable */ + tokenSpace +						   (((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);			if (zc->workSpaceSize < neededSpace) {				ZSTD_free(zc->workSpace, zc->customMem);				zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);				if (zc->workSpace == NULL)					return ERROR(memory_allocation);				zc->workSpaceSize = neededSpace;			}		} 		if (crp != ZSTDcrp_noMemset)			memset(zc->workSpace, 0, tableSpace); /* reset tables only */		xxh64_reset(&zc->xxhState, 0);		zc->hashLog3 = hashLog3;		zc->hashTable = (U32 *)(zc->workSpace);		zc->chainTable = zc->hashTable + hSize;		zc->hashTable3 = zc->chainTable + chainSize;		ptr = zc->hashTable3 + h3Size;		zc->hufTable = (HUF_CElt *)ptr;		zc->flagStaticTables = 0;		zc->flagStaticHufTable = HUF_repeat_none;		ptr = ((U32 *)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */ 		zc->nextToUpdate = 1;		zc->nextSrc = NULL;		zc->base = NULL;		zc->dictBase = NULL;		zc->dictLimit = 0;		zc->lowLimit = 0;		zc->params = params;		zc->blockSize = blockSize;		zc->frameContentSize = frameContentSize;		{			int i;			for (i = 0; i < ZSTD_REP_NUM; i++)				zc->rep[i] = repStartValue[i];		} 		if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) {			zc->seqStore.litFreq = (U32 *)ptr;			zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1 << Litbits);			zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL + 1);			zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML + 1);			ptr = zc->seqStore.offCodeFreq + (MaxOff + 1);			zc->seqStore.matchTable = (ZSTD_match_t *)ptr;			ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM + 1;			zc->seqStore.priceTable = (ZSTD_optimal_t *)ptr;			ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM + 1;			zc->seqStore.litLengthSum = 0;		}		zc->seqStore.sequencesStart = (seqDef *)ptr;		ptr = zc->seqStore.sequencesStart + maxNbSeq;		zc->seqStore.llCode = (BYTE *)ptr;		zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;		zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;		zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq; 		zc->stage = ZSTDcs_init;		zc->dictID = 0;		zc->loadedDictEnd = 0; 		return 0;	}} /* ZSTD_invalidateRepCodes() : * ensures next compression will not use repcodes from previous block. * Note : only works with regular variant; *        do not use with extDict variant ! */void ZSTD_invalidateRepCodes(ZSTD_CCtx *cctx){	int i;	for (i = 0; i < ZSTD_REP_NUM; i++)		cctx->rep[i] = 0;} /*! ZSTD_copyCCtx() :*   Duplicate an existing context `srcCCtx` into another one `dstCCtx`.*   Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).*   @return : 0, or an error code */size_t ZSTD_copyCCtx(ZSTD_CCtx *dstCCtx, const ZSTD_CCtx *srcCCtx, unsigned long long pledgedSrcSize){	if (srcCCtx->stage != ZSTDcs_init)		return ERROR(stage_wrong); 	memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));	{		ZSTD_parameters params = srcCCtx->params;		params.fParams.contentSizeFlag = (pledgedSrcSize > 0);		ZSTD_resetCCtx_advanced(dstCCtx, params, pledgedSrcSize, ZSTDcrp_noMemset);	} 	/* copy tables */	{		size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);		size_t const hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;		size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;		size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);		memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);	} 	/* copy dictionary offsets */	dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;	dstCCtx->nextToUpdate3 = srcCCtx->nextToUpdate3;	dstCCtx->nextSrc = srcCCtx->nextSrc;	dstCCtx->base = srcCCtx->base;	dstCCtx->dictBase = srcCCtx->dictBase;	dstCCtx->dictLimit = srcCCtx->dictLimit;	dstCCtx->lowLimit = srcCCtx->lowLimit;	dstCCtx->loadedDictEnd = srcCCtx->loadedDictEnd;	dstCCtx->dictID = srcCCtx->dictID; 	/* copy entropy tables */	dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;	dstCCtx->flagStaticHufTable = srcCCtx->flagStaticHufTable;	if (srcCCtx->flagStaticTables) {		memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));		memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));		memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));	}	if (srcCCtx->flagStaticHufTable) {		memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256 * 4);	} 	return 0;} /*! ZSTD_reduceTable() :*   reduce table indexes by `reducerValue` */static void ZSTD_reduceTable(U32 *const table, U32 const size, U32 const reducerValue){	U32 u;	for (u = 0; u < size; u++) {		if (table[u] < reducerValue)			table[u] = 0;		else			table[u] -= reducerValue;	}} /*! ZSTD_reduceIndex() :*   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->params.cParams.hashLog;		ZSTD_reduceTable(zc->hashTable, hSize, reducerValue);	} 	{		U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);		ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue);	} 	{		U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;		ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue);	}} /*-********************************************************  Block entropic compression*********************************************************/ /* See doc/zstd_compression_format.md for detailed format description */ size_t ZSTD_noCompressBlock(void *dst, size_t dstCapacity, const void *src, size_t srcSize){	if (srcSize + ZSTD_blockHeaderSize > dstCapacity)		return ERROR(dstSize_tooSmall);	memcpy((BYTE *)dst + ZSTD_blockHeaderSize, src, srcSize);	ZSTD_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);	return ZSTD_blockHeaderSize + srcSize;} static size_t ZSTD_noCompressLiterals(void *dst, size_t dstCapacity, const void *src, size_t srcSize){	BYTE *const ostart = (BYTE * const)dst;	U32 const flSize = 1 + (srcSize > 31) + (srcSize > 4095); 	if (srcSize + flSize > dstCapacity)		return ERROR(dstSize_tooSmall); 	switch (flSize) {	case 1: /* 2 - 1 - 5 */ ostart[0] = (BYTE)((U32)set_basic + (srcSize << 3)); break;	case 2: /* 2 - 2 - 12 */ ZSTD_writeLE16(ostart, (U16)((U32)set_basic + (1 << 2) + (srcSize << 4))); break;	default: /*note : should not be necessary : flSize is within {1,2,3} */	case 3: /* 2 - 2 - 20 */ ZSTD_writeLE32(ostart, (U32)((U32)set_basic + (3 << 2) + (srcSize << 4))); break;	} 	memcpy(ostart + flSize, src, srcSize);	return srcSize + flSize;} static size_t ZSTD_compressRleLiteralsBlock(void *dst, size_t dstCapacity, const void *src, size_t srcSize){	BYTE *const ostart = (BYTE * const)dst;	U32 const flSize = 1 + (srcSize > 31) + (srcSize > 4095); 	(void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */ 	switch (flSize) {	case 1: /* 2 - 1 - 5 */ ostart[0] = (BYTE)((U32)set_rle + (srcSize << 3)); break;	case 2: /* 2 - 2 - 12 */ ZSTD_writeLE16(ostart, (U16)((U32)set_rle + (1 << 2) + (srcSize << 4))); break;	default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */	case 3: /* 2 - 2 - 20 */ ZSTD_writeLE32(ostart, (U32)((U32)set_rle + (3 << 2) + (srcSize << 4))); break;	} 	ostart[flSize] = *(const BYTE *)src;	return flSize + 1;} static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; } static size_t ZSTD_compressLiterals(ZSTD_CCtx *zc, void *dst, size_t dstCapacity, const void *src, size_t srcSize){	size_t const minGain = ZSTD_minGain(srcSize);	size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);	BYTE *const ostart = (BYTE *)dst;	U32 singleStream = srcSize < 256;	symbolEncodingType_e hType = set_compressed;	size_t cLitSize; /* small ? don't even attempt compression (speed opt) */#define LITERAL_NOENTROPY 63	{		size_t const minLitSize = zc->flagStaticHufTable == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;		if (srcSize <= minLitSize)			return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);	} 	if (dstCapacity < lhSize + 1)		return ERROR(dstSize_tooSmall); /* not enough space for compression */

Lines 1–500 of 3485.