Compress-Zstd

 view release on metacpan or  search on metacpan

ext/zstd/contrib/linux-kernel/lib/zstd/decompress.c  view on Meta::CPAN


		ip += headerSize;
		remainingSize -= headerSize;

		/* Loop on each block */
		while (1) {
			blockProperties_t blockProperties;
			size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);
			if (ZSTD_isError(cBlockSize))
				return cBlockSize;

			if (ZSTD_blockHeaderSize + cBlockSize > remainingSize)
				return ERROR(srcSize_wrong);

			ip += ZSTD_blockHeaderSize + cBlockSize;
			remainingSize -= ZSTD_blockHeaderSize + cBlockSize;

			if (blockProperties.lastBlock)
				break;
		}

		if (fParams.checksumFlag) { /* Frame content checksum */
			if (remainingSize < 4)
				return ERROR(srcSize_wrong);
			ip += 4;
			remainingSize -= 4;
		}

		return ip - ipstart;
	}
}

/*! ZSTD_decompressFrame() :
*   @dctx must be properly initialized */
static size_t ZSTD_decompressFrame(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void **srcPtr, size_t *srcSizePtr)
{
	const BYTE *ip = (const BYTE *)(*srcPtr);
	BYTE *const ostart = (BYTE * const)dst;
	BYTE *const oend = ostart + dstCapacity;
	BYTE *op = ostart;
	size_t remainingSize = *srcSizePtr;

	/* check */
	if (remainingSize < ZSTD_frameHeaderSize_min + ZSTD_blockHeaderSize)
		return ERROR(srcSize_wrong);

	/* Frame Header */
	{
		size_t const frameHeaderSize = ZSTD_frameHeaderSize(ip, ZSTD_frameHeaderSize_prefix);
		if (ZSTD_isError(frameHeaderSize))
			return frameHeaderSize;
		if (remainingSize < frameHeaderSize + ZSTD_blockHeaderSize)
			return ERROR(srcSize_wrong);
		CHECK_F(ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize));
		ip += frameHeaderSize;
		remainingSize -= frameHeaderSize;
	}

	/* Loop on each block */
	while (1) {
		size_t decodedSize;
		blockProperties_t blockProperties;
		size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);
		if (ZSTD_isError(cBlockSize))
			return cBlockSize;

		ip += ZSTD_blockHeaderSize;
		remainingSize -= ZSTD_blockHeaderSize;
		if (cBlockSize > remainingSize)
			return ERROR(srcSize_wrong);

		switch (blockProperties.blockType) {
		case bt_compressed: decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend - op, ip, cBlockSize); break;
		case bt_raw: decodedSize = ZSTD_copyRawBlock(op, oend - op, ip, cBlockSize); break;
		case bt_rle: decodedSize = ZSTD_generateNxBytes(op, oend - op, *ip, blockProperties.origSize); break;
		case bt_reserved:
		default: return ERROR(corruption_detected);
		}

		if (ZSTD_isError(decodedSize))
			return decodedSize;
		if (dctx->fParams.checksumFlag)
			xxh64_update(&dctx->xxhState, op, decodedSize);
		op += decodedSize;
		ip += cBlockSize;
		remainingSize -= cBlockSize;
		if (blockProperties.lastBlock)
			break;
	}

	if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */
		U32 const checkCalc = (U32)xxh64_digest(&dctx->xxhState);
		U32 checkRead;
		if (remainingSize < 4)
			return ERROR(checksum_wrong);
		checkRead = ZSTD_readLE32(ip);
		if (checkRead != checkCalc)
			return ERROR(checksum_wrong);
		ip += 4;
		remainingSize -= 4;
	}

	/* Allow caller to get size read */
	*srcPtr = ip;
	*srcSizePtr = remainingSize;
	return op - ostart;
}

static const void *ZSTD_DDictDictContent(const ZSTD_DDict *ddict);
static size_t ZSTD_DDictDictSize(const ZSTD_DDict *ddict);

static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const void *dict, size_t dictSize,
					const ZSTD_DDict *ddict)
{
	void *const dststart = dst;

	if (ddict) {
		if (dict) {
			/* programmer error, these two cases should be mutually exclusive */
			return ERROR(GENERIC);
		}

		dict = ZSTD_DDictDictContent(ddict);
		dictSize = ZSTD_DDictDictSize(ddict);
	}

	while (srcSize >= ZSTD_frameHeaderSize_prefix) {
		U32 magicNumber;

		magicNumber = ZSTD_readLE32(src);
		if (magicNumber != ZSTD_MAGICNUMBER) {
			if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
				size_t skippableSize;
				if (srcSize < ZSTD_skippableHeaderSize)
					return ERROR(srcSize_wrong);
				skippableSize = ZSTD_readLE32((const BYTE *)src + 4) + ZSTD_skippableHeaderSize;
				if (srcSize < skippableSize) {
					return ERROR(srcSize_wrong);
				}

				src = (const BYTE *)src + skippableSize;
				srcSize -= skippableSize;
				continue;
			} else {

ext/zstd/contrib/linux-kernel/lib/zstd/decompress.c  view on Meta::CPAN

		{
			size_t const errorCode = ZSTD_loadEntropy_inDDict(ddict);
			if (ZSTD_isError(errorCode)) {
				ZSTD_freeDDict(ddict);
				return NULL;
			}
		}

		return ddict;
	}
}

/*! ZSTD_initDDict() :
*   Create a digested dictionary, to start decompression without startup delay.
*   `dict` content is copied inside DDict.
*   Consequently, `dict` can be released after `ZSTD_DDict` creation */
ZSTD_DDict *ZSTD_initDDict(const void *dict, size_t dictSize, void *workspace, size_t workspaceSize)
{
	ZSTD_customMem const stackMem = ZSTD_initStack(workspace, workspaceSize);
	return ZSTD_createDDict_advanced(dict, dictSize, 1, stackMem);
}

size_t ZSTD_freeDDict(ZSTD_DDict *ddict)
{
	if (ddict == NULL)
		return 0; /* support free on NULL */
	{
		ZSTD_customMem const cMem = ddict->cMem;
		ZSTD_free(ddict->dictBuffer, cMem);
		ZSTD_free(ddict, cMem);
		return 0;
	}
}

/*! ZSTD_getDictID_fromDict() :
 *  Provides the dictID stored within dictionary.
 *  if @return == 0, the dictionary is not conformant with Zstandard specification.
 *  It can still be loaded, but as a content-only dictionary. */
unsigned ZSTD_getDictID_fromDict(const void *dict, size_t dictSize)
{
	if (dictSize < 8)
		return 0;
	if (ZSTD_readLE32(dict) != ZSTD_DICT_MAGIC)
		return 0;
	return ZSTD_readLE32((const char *)dict + 4);
}

/*! ZSTD_getDictID_fromDDict() :
 *  Provides the dictID of the dictionary loaded into `ddict`.
 *  If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
 *  Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict *ddict)
{
	if (ddict == NULL)
		return 0;
	return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize);
}

/*! ZSTD_getDictID_fromFrame() :
 *  Provides the dictID required to decompressed the frame stored within `src`.
 *  If @return == 0, the dictID could not be decoded.
 *  This could for one of the following reasons :
 *  - The frame does not require a dictionary to be decoded (most common case).
 *  - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden information.
 *    Note : this use case also happens when using a non-conformant dictionary.
 *  - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`).
 *  - This is not a Zstandard frame.
 *  When identifying the exact failure cause, it's possible to used ZSTD_getFrameParams(), which will provide a more precise error code. */
unsigned ZSTD_getDictID_fromFrame(const void *src, size_t srcSize)
{
	ZSTD_frameParams zfp = {0, 0, 0, 0};
	size_t const hError = ZSTD_getFrameParams(&zfp, src, srcSize);
	if (ZSTD_isError(hError))
		return 0;
	return zfp.dictID;
}

/*! ZSTD_decompress_usingDDict() :
*   Decompression using a pre-digested Dictionary
*   Use dictionary without significant overhead. */
size_t ZSTD_decompress_usingDDict(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const ZSTD_DDict *ddict)
{
	/* pass content and size in case legacy frames are encountered */
	return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, NULL, 0, ddict);
}

/*=====================================
*   Streaming decompression
*====================================*/

typedef enum { zdss_init, zdss_loadHeader, zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage;

/* *** Resource management *** */
struct ZSTD_DStream_s {
	ZSTD_DCtx *dctx;
	ZSTD_DDict *ddictLocal;
	const ZSTD_DDict *ddict;
	ZSTD_frameParams fParams;
	ZSTD_dStreamStage stage;
	char *inBuff;
	size_t inBuffSize;
	size_t inPos;
	size_t maxWindowSize;
	char *outBuff;
	size_t outBuffSize;
	size_t outStart;
	size_t outEnd;
	size_t blockSize;
	BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; /* tmp buffer to store frame header */
	size_t lhSize;
	ZSTD_customMem customMem;
	void *legacyContext;
	U32 previousLegacyVersion;
	U32 legacyVersion;
	U32 hostageByte;
}; /* typedef'd to ZSTD_DStream within "zstd.h" */

size_t ZSTD_DStreamWorkspaceBound(size_t maxWindowSize)
{
	size_t const blockSize = MIN(maxWindowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX);
	size_t const inBuffSize = blockSize;
	size_t const outBuffSize = maxWindowSize + blockSize + WILDCOPY_OVERLENGTH * 2;
	return ZSTD_DCtxWorkspaceBound() + ZSTD_ALIGN(sizeof(ZSTD_DStream)) + ZSTD_ALIGN(inBuffSize) + ZSTD_ALIGN(outBuffSize);
}

static ZSTD_DStream *ZSTD_createDStream_advanced(ZSTD_customMem customMem)

ext/zstd/contrib/linux-kernel/lib/zstd/decompress.c  view on Meta::CPAN

				break;
			}

			/* check for single-pass mode opportunity */
			if (zds->fParams.frameContentSize && zds->fParams.windowSize /* skippable frame if == 0 */
			    && (U64)(size_t)(oend - op) >= zds->fParams.frameContentSize) {
				size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend - istart);
				if (cSize <= (size_t)(iend - istart)) {
					size_t const decompressedSize = ZSTD_decompress_usingDDict(zds->dctx, op, oend - op, istart, cSize, zds->ddict);
					if (ZSTD_isError(decompressedSize))
						return decompressedSize;
					ip = istart + cSize;
					op += decompressedSize;
					zds->dctx->expected = 0;
					zds->stage = zdss_init;
					someMoreWork = 0;
					break;
				}
			}

			/* Consume header */
			ZSTD_refDDict(zds->dctx, zds->ddict);
			{
				size_t const h1Size = ZSTD_nextSrcSizeToDecompress(zds->dctx); /* == ZSTD_frameHeaderSize_prefix */
				CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer, h1Size));
				{
					size_t const h2Size = ZSTD_nextSrcSizeToDecompress(zds->dctx);
					CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer + h1Size, h2Size));
				}
			}

			zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
			if (zds->fParams.windowSize > zds->maxWindowSize)
				return ERROR(frameParameter_windowTooLarge);

			/* Buffers are preallocated, but double check */
			{
				size_t const blockSize = MIN(zds->maxWindowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX);
				size_t const neededOutSize = zds->maxWindowSize + blockSize + WILDCOPY_OVERLENGTH * 2;
				if (zds->inBuffSize < blockSize) {
					return ERROR(GENERIC);
				}
				if (zds->outBuffSize < neededOutSize) {
					return ERROR(GENERIC);
				}
				zds->blockSize = blockSize;
			}
			zds->stage = zdss_read;
		}
		/* pass-through */

		case zdss_read: {
			size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx);
			if (neededInSize == 0) { /* end of frame */
				zds->stage = zdss_init;
				someMoreWork = 0;
				break;
			}
			if ((size_t)(iend - ip) >= neededInSize) { /* decode directly from src */
				const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx);
				size_t const decodedSize = ZSTD_decompressContinue(zds->dctx, zds->outBuff + zds->outStart,
										   (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart), ip, neededInSize);
				if (ZSTD_isError(decodedSize))
					return decodedSize;
				ip += neededInSize;
				if (!decodedSize && !isSkipFrame)
					break; /* this was just a header */
				zds->outEnd = zds->outStart + decodedSize;
				zds->stage = zdss_flush;
				break;
			}
			if (ip == iend) {
				someMoreWork = 0;
				break;
			} /* no more input */
			zds->stage = zdss_load;
			/* pass-through */
		}

		case zdss_load: {
			size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx);
			size_t const toLoad = neededInSize - zds->inPos; /* should always be <= remaining space within inBuff */
			size_t loadedSize;
			if (toLoad > zds->inBuffSize - zds->inPos)
				return ERROR(corruption_detected); /* should never happen */
			loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend - ip);
			ip += loadedSize;
			zds->inPos += loadedSize;
			if (loadedSize < toLoad) {
				someMoreWork = 0;
				break;
			} /* not enough input, wait for more */

			/* decode loaded input */
			{
				const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx);
				size_t const decodedSize = ZSTD_decompressContinue(zds->dctx, zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart,
										   zds->inBuff, neededInSize);
				if (ZSTD_isError(decodedSize))
					return decodedSize;
				zds->inPos = 0; /* input is consumed */
				if (!decodedSize && !isSkipFrame) {
					zds->stage = zdss_read;
					break;
				} /* this was just a header */
				zds->outEnd = zds->outStart + decodedSize;
				zds->stage = zdss_flush;
				/* pass-through */
			}
		}

		case zdss_flush: {
			size_t const toFlushSize = zds->outEnd - zds->outStart;
			size_t const flushedSize = ZSTD_limitCopy(op, oend - op, zds->outBuff + zds->outStart, toFlushSize);
			op += flushedSize;
			zds->outStart += flushedSize;
			if (flushedSize == toFlushSize) { /* flush completed */
				zds->stage = zdss_read;
				if (zds->outStart + zds->blockSize > zds->outBuffSize)
					zds->outStart = zds->outEnd = 0;
				break;
			}
			/* cannot complete flush */
			someMoreWork = 0;
			break;
		}
		default:
			return ERROR(GENERIC); /* impossible */
		}
	}

	/* result */
	input->pos += (size_t)(ip - istart);
	output->pos += (size_t)(op - ostart);
	{
		size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds->dctx);
		if (!nextSrcSizeHint) {			    /* frame fully decoded */
			if (zds->outEnd == zds->outStart) { /* output fully flushed */
				if (zds->hostageByte) {
					if (input->pos >= input->size) {
						zds->stage = zdss_read;
						return 1;
					}	     /* can't release hostage (not present) */
					input->pos++; /* release hostage */
				}
				return 0;
			}
			if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */
				input->pos--;    /* note : pos > 0, otherwise, impossible to finish reading last block */
				zds->hostageByte = 1;
			}
			return 1;
		}
		nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds->dctx) == ZSTDnit_block); /* preload header of next block */
		if (zds->inPos > nextSrcSizeHint)
			return ERROR(GENERIC); /* should never happen */
		nextSrcSizeHint -= zds->inPos; /* already loaded*/
		return nextSrcSizeHint;
	}
}

EXPORT_SYMBOL(ZSTD_DCtxWorkspaceBound);
EXPORT_SYMBOL(ZSTD_initDCtx);
EXPORT_SYMBOL(ZSTD_decompressDCtx);
EXPORT_SYMBOL(ZSTD_decompress_usingDict);

EXPORT_SYMBOL(ZSTD_DDictWorkspaceBound);
EXPORT_SYMBOL(ZSTD_initDDict);
EXPORT_SYMBOL(ZSTD_decompress_usingDDict);

EXPORT_SYMBOL(ZSTD_DStreamWorkspaceBound);
EXPORT_SYMBOL(ZSTD_initDStream);
EXPORT_SYMBOL(ZSTD_initDStream_usingDDict);
EXPORT_SYMBOL(ZSTD_resetDStream);
EXPORT_SYMBOL(ZSTD_decompressStream);
EXPORT_SYMBOL(ZSTD_DStreamInSize);
EXPORT_SYMBOL(ZSTD_DStreamOutSize);

EXPORT_SYMBOL(ZSTD_findFrameCompressedSize);
EXPORT_SYMBOL(ZSTD_getFrameContentSize);
EXPORT_SYMBOL(ZSTD_findDecompressedSize);

EXPORT_SYMBOL(ZSTD_isFrame);
EXPORT_SYMBOL(ZSTD_getDictID_fromDict);
EXPORT_SYMBOL(ZSTD_getDictID_fromDDict);
EXPORT_SYMBOL(ZSTD_getDictID_fromFrame);

EXPORT_SYMBOL(ZSTD_getFrameParams);
EXPORT_SYMBOL(ZSTD_decompressBegin);
EXPORT_SYMBOL(ZSTD_decompressBegin_usingDict);
EXPORT_SYMBOL(ZSTD_copyDCtx);
EXPORT_SYMBOL(ZSTD_nextSrcSizeToDecompress);
EXPORT_SYMBOL(ZSTD_decompressContinue);
EXPORT_SYMBOL(ZSTD_nextInputType);

EXPORT_SYMBOL(ZSTD_decompressBlock);
EXPORT_SYMBOL(ZSTD_insertBlock);



( run in 0.810 second using v1.01-cache-2.11-cpan-39bf76dae61 )