Merge remote-tracking branch 'refs/remotes/Cyan4973/dev060' into repcodes

# Conflicts:
#	lib/zstd_decompress.c
#	programs/bench.c
This commit is contained in:
inikep 2016-03-18 11:14:58 +01:00
commit 5b15865413
19 changed files with 721 additions and 633 deletions

6
NEWS
View File

@ -1,3 +1,9 @@
v0.6.0
Stronger high compression modes, thanks to Przemyslaw Skibinski
API : ZSTD_getFrameParams() provides size of decompressed content
New : highest compression modes require `--ultra` command to fully unleash their capacity
Fixed : zstd cli return error code > 0 and removes dst file artifact when decompression fails, thanks to Chip Turner
v0.5.1 v0.5.1
New : Optimal parsing => Very high compression modes, thanks to Przemyslaw Skibinski New : Optimal parsing => Very high compression modes, thanks to Przemyslaw Skibinski
Changed : Dictionary builder integrated into libzstd and zstd cli Changed : Dictionary builder integrated into libzstd and zstd cli

View File

@ -40,17 +40,18 @@
***************************************/ ***************************************/
#include <stdlib.h> #include <stdlib.h>
#include "error_private.h" #include "error_private.h"
#include "zstd_static.h" #include "zstd_internal.h" /* MIN, ZSTD_blockHeaderSize */
#include "zstd_static.h" /* ZSTD_BLOCKSIZE_MAX */
#include "zbuff_static.h" #include "zbuff_static.h"
/* ************************************* /* *************************************
* Constants * Constants
***************************************/ ***************************************/
static size_t ZBUFF_blockHeaderSize = 3; static size_t const ZBUFF_endFrameSize = ZSTD_BLOCKHEADERSIZE;
static size_t ZBUFF_endFrameSize = 3;
/** ************************************************
/*_**************************************************
* Streaming compression * Streaming compression
* *
* A ZBUFF_CCtx object is required to track streaming operation. * A ZBUFF_CCtx object is required to track streaming operation.
@ -59,28 +60,28 @@ static size_t ZBUFF_endFrameSize = 3;
* ZBUFF_CCtx objects can be reused multiple times. * ZBUFF_CCtx objects can be reused multiple times.
* *
* Use ZBUFF_compressContinue() repetitively to consume your input. * Use ZBUFF_compressContinue() repetitively to consume your input.
* *srcSizePtr and *maxDstSizePtr can be any size. * *srcSizePtr and *dstCapacityPtr can be any size.
* The function will report how many bytes were read or written by modifying *srcSizePtr and *maxDstSizePtr. * The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr.
* Note that it may not consume the entire input, in which case it's up to the caller to call again the function with remaining input. * Note that it may not consume the entire input, in which case it's up to the caller to call again the function with remaining input.
* The content of dst will be overwritten (up to *maxDstSizePtr) at each function call, so save its content if it matters or change dst . * The content of dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters or change dst .
* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency) * @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency)
* or an error code, which can be tested using ZBUFF_isError(). * or an error code, which can be tested using ZBUFF_isError().
* *
* ZBUFF_compressFlush() can be used to instruct ZBUFF to compress and output whatever remains within its buffer. * ZBUFF_compressFlush() can be used to instruct ZBUFF to compress and output whatever remains within its buffer.
* Note that it will not output more than *maxDstSizePtr. * Note that it will not output more than *dstCapacityPtr.
* Therefore, some content might still be left into its internal buffer if dst buffer is too small. * Therefore, some content might still be left into its internal buffer if dst buffer is too small.
* @return : nb of bytes still present into internal buffer (0 if it's empty) * @return : nb of bytes still present into internal buffer (0 if it's empty)
* or an error code, which can be tested using ZBUFF_isError(). * or an error code, which can be tested using ZBUFF_isError().
* *
* ZBUFF_compressEnd() instructs to finish a frame. * ZBUFF_compressEnd() instructs to finish a frame.
* It will perform a flush and write frame epilogue. * It will perform a flush and write frame epilogue.
* Similar to ZBUFF_compressFlush(), it may not be able to output the entire internal buffer content if *maxDstSizePtr is too small. * Similar to ZBUFF_compressFlush(), it may not be able to output the entire internal buffer content if *dstCapacityPtr is too small.
* @return : nb of bytes still present into internal buffer (0 if it's empty) * @return : nb of bytes still present into internal buffer (0 if it's empty)
* or an error code, which can be tested using ZBUFF_isError(). * or an error code, which can be tested using ZBUFF_isError().
* *
* Hint : recommended buffer sizes (not compulsory) * Hint : recommended buffer sizes (not compulsory)
* input : 128 KB block size is the internal unit, it improves latency to use this value. * input : ZSTD_BLOCKSIZE_MAX (128 KB), internal unit size, it improves latency to use this value.
* output : ZSTD_compressBound(128 KB) + 3 + 3 : ensures it's always possible to write/flush/end a full block at best speed. * output : ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + ZBUFF_endFrameSize : ensures it's always possible to write/flush/end a full block at best speed.
* **************************************************/ * **************************************************/
typedef enum { ZBUFFcs_init, ZBUFFcs_load, ZBUFFcs_flush } ZBUFF_cStage; typedef enum { ZBUFFcs_init, ZBUFFcs_load, ZBUFFcs_flush } ZBUFF_cStage;
@ -88,13 +89,13 @@ typedef enum { ZBUFFcs_init, ZBUFFcs_load, ZBUFFcs_flush } ZBUFF_cStage;
/* *** Ressources *** */ /* *** Ressources *** */
struct ZBUFF_CCtx_s { struct ZBUFF_CCtx_s {
ZSTD_CCtx* zc; ZSTD_CCtx* zc;
char* inBuff; char* inBuff;
size_t inBuffSize; size_t inBuffSize;
size_t inToCompress; size_t inToCompress;
size_t inBuffPos; size_t inBuffPos;
size_t inBuffTarget; size_t inBuffTarget;
size_t blockSize; size_t blockSize;
char* outBuff; char* outBuff;
size_t outBuffSize; size_t outBuffSize;
size_t outBuffContentSize; size_t outBuffContentSize;
size_t outBuffFlushedSize; size_t outBuffFlushedSize;
@ -123,8 +124,6 @@ size_t ZBUFF_freeCCtx(ZBUFF_CCtx* zbc)
/* *** Initialization *** */ /* *** Initialization *** */
#define MIN(a,b) ( ((a)<(b)) ? (a) : (b) )
#define BLOCKSIZE (128 * 1024) /* a bit too "magic", should come from reference */
size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, const void* dict, size_t dictSize, ZSTD_parameters params) size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, const void* dict, size_t dictSize, ZSTD_parameters params)
{ {
size_t neededInBuffSize; size_t neededInBuffSize;
@ -139,7 +138,7 @@ size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, const void* dict, size_t dic
zbc->inBuff = (char*)malloc(neededInBuffSize); zbc->inBuff = (char*)malloc(neededInBuffSize);
if (zbc->inBuff == NULL) return ERROR(memory_allocation); if (zbc->inBuff == NULL) return ERROR(memory_allocation);
} }
zbc->blockSize = MIN(BLOCKSIZE, zbc->inBuffSize); zbc->blockSize = MIN(ZSTD_BLOCKSIZE_MAX, zbc->inBuffSize);
if (zbc->outBuffSize < ZSTD_compressBound(zbc->blockSize)+1) { if (zbc->outBuffSize < ZSTD_compressBound(zbc->blockSize)+1) {
zbc->outBuffSize = ZSTD_compressBound(zbc->blockSize)+1; zbc->outBuffSize = ZSTD_compressBound(zbc->blockSize)+1;
free(zbc->outBuff); /* should not be necessary */ free(zbc->outBuff); /* should not be necessary */
@ -172,15 +171,15 @@ ZSTDLIB_API size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* zbc, const void* dic
/* *** Compression *** */ /* *** Compression *** */
static size_t ZBUFF_limitCopy(void* dst, size_t maxDstSize, const void* src, size_t srcSize) static size_t ZBUFF_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
{ {
size_t length = MIN(maxDstSize, srcSize); size_t length = MIN(dstCapacity, srcSize);
memcpy(dst, src, length); memcpy(dst, src, length);
return length; return length;
} }
static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc, static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc,
void* dst, size_t* maxDstSizePtr, void* dst, size_t* dstCapacityPtr,
const void* src, size_t* srcSizePtr, const void* src, size_t* srcSizePtr,
int flush) /* aggregate : wait for full block before compressing */ int flush) /* aggregate : wait for full block before compressing */
{ {
@ -190,7 +189,7 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc,
const char* const iend = istart + *srcSizePtr; const char* const iend = istart + *srcSizePtr;
char* const ostart = (char*)dst; char* const ostart = (char*)dst;
char* op = ostart; char* op = ostart;
char* const oend = ostart + *maxDstSizePtr; char* const oend = ostart + *dstCapacityPtr;
while (notDone) { while (notDone) {
switch(zbc->stage) switch(zbc->stage)
@ -250,7 +249,7 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc,
} }
*srcSizePtr = ip - istart; *srcSizePtr = ip - istart;
*maxDstSizePtr = op - ostart; *dstCapacityPtr = op - ostart;
{ {
size_t hintInSize = zbc->inBuffTarget - zbc->inBuffPos; size_t hintInSize = zbc->inBuffTarget - zbc->inBuffPos;
if (hintInSize==0) hintInSize = zbc->blockSize; if (hintInSize==0) hintInSize = zbc->blockSize;
@ -259,30 +258,30 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc,
} }
size_t ZBUFF_compressContinue(ZBUFF_CCtx* zbc, size_t ZBUFF_compressContinue(ZBUFF_CCtx* zbc,
void* dst, size_t* maxDstSizePtr, void* dst, size_t* dstCapacityPtr,
const void* src, size_t* srcSizePtr) const void* src, size_t* srcSizePtr)
{ {
return ZBUFF_compressContinue_generic(zbc, dst, maxDstSizePtr, src, srcSizePtr, 0); return ZBUFF_compressContinue_generic(zbc, dst, dstCapacityPtr, src, srcSizePtr, 0);
} }
/* *** Finalize *** */ /* *** Finalize *** */
size_t ZBUFF_compressFlush(ZBUFF_CCtx* zbc, void* dst, size_t* maxDstSizePtr) size_t ZBUFF_compressFlush(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr)
{ {
size_t srcSize = 0; size_t srcSize = 0;
ZBUFF_compressContinue_generic(zbc, dst, maxDstSizePtr, &srcSize, &srcSize, 1); /* use a valid src address instead of NULL, as some sanitizer don't like it */ ZBUFF_compressContinue_generic(zbc, dst, dstCapacityPtr, &srcSize, &srcSize, 1); /* use a valid src address instead of NULL, as some sanitizer don't like it */
return zbc->outBuffContentSize - zbc->outBuffFlushedSize; return zbc->outBuffContentSize - zbc->outBuffFlushedSize;
} }
size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* maxDstSizePtr) size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr)
{ {
BYTE* const ostart = (BYTE*)dst; BYTE* const ostart = (BYTE*)dst;
BYTE* op = ostart; BYTE* op = ostart;
BYTE* const oend = ostart + *maxDstSizePtr; BYTE* const oend = ostart + *dstCapacityPtr;
size_t outSize = *maxDstSizePtr; size_t outSize = *dstCapacityPtr;
size_t epilogueSize, remaining; size_t epilogueSize, remaining;
ZBUFF_compressFlush(zbc, dst, &outSize); /* flush any remaining inBuff */ ZBUFF_compressFlush(zbc, dst, &outSize); /* flush any remaining inBuff */
op += outSize; op += outSize;
@ -293,43 +292,42 @@ size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* maxDstSizePtr)
remaining = ZBUFF_compressFlush(zbc, op, &outSize); /* attempt to flush epilogue into dst */ remaining = ZBUFF_compressFlush(zbc, op, &outSize); /* attempt to flush epilogue into dst */
op += outSize; op += outSize;
if (!remaining) zbc->stage = ZBUFFcs_init; /* close only if nothing left to flush */ if (!remaining) zbc->stage = ZBUFFcs_init; /* close only if nothing left to flush */
*maxDstSizePtr = op-ostart; /* tells how many bytes were written */ *dstCapacityPtr = op-ostart; /* tells how many bytes were written */
return remaining; return remaining;
} }
/*-***************************************************************************
/** ************************************************ * Streaming decompression howto
* Streaming decompression
* *
* A ZBUFF_DCtx object is required to track streaming operation. * A ZBUFF_DCtx object is required to track streaming operations.
* Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources. * Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources.
* Use ZBUFF_decompressInit() to start a new decompression operation. * Use ZBUFF_decompressInit() to start a new decompression operation,
* ZBUFF_DCtx objects can be reused multiple times. * or ZBUFF_decompressInitDictionary() if decompression requires a dictionary.
* Note that ZBUFF_DCtx objects can be re-init multiple times.
* *
* Use ZBUFF_decompressContinue() repetitively to consume your input. * Use ZBUFF_decompressContinue() repetitively to consume your input.
* *srcSizePtr and *maxDstSizePtr can be any size. * *srcSizePtr and *dstCapacityPtr can be any size.
* The function will report how many bytes were read or written by modifying *srcSizePtr and *maxDstSizePtr. * The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr.
* Note that it may not consume the entire input, in which case it's up to the caller to call again the function with remaining input. * Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again.
* The content of dst will be overwritten (up to *maxDstSizePtr) at each function call, so save its content if it matters or change dst . * The content of @dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters, or change @dst.
* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency) * @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to help latency),
* or 0 when a frame is completely decoded * or 0 when a frame is completely decoded,
* or an error code, which can be tested using ZBUFF_isError(). * or an error code, which can be tested using ZBUFF_isError().
* *
* Hint : recommended buffer sizes (not compulsory) * Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize() and ZBUFF_recommendedDOutSize()
* output : 128 KB block size is the internal unit, it ensures it's always possible to write a full block when it's decoded. * output : ZBUFF_recommendedDOutSize==128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded.
* input : just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . * input : ZBUFF_recommendedDInSize == 128KB + 3;
* **************************************************/ * just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 .
* *******************************************************************************/
typedef enum { ZBUFFds_init, ZBUFFds_readHeader, ZBUFFds_loadHeader, ZBUFFds_decodeHeader, typedef enum { ZBUFFds_init, ZBUFFds_readHeader,
ZBUFFds_read, ZBUFFds_load, ZBUFFds_flush } ZBUFF_dStage; ZBUFFds_read, ZBUFFds_load, ZBUFFds_flush } ZBUFF_dStage;
/* *** Resource management *** */ /* *** Resource management *** */
#define ZSTD_frameHeaderSize_max 5 /* too magical, should come from reference */
struct ZBUFF_DCtx_s { struct ZBUFF_DCtx_s {
ZSTD_DCtx* zc; ZSTD_DCtx* zc;
ZSTD_parameters params; ZSTD_frameParams fParams;
char* inBuff; char* inBuff;
size_t inBuffSize; size_t inBuffSize;
size_t inPos; size_t inPos;
@ -337,9 +335,7 @@ struct ZBUFF_DCtx_s {
size_t outBuffSize; size_t outBuffSize;
size_t outStart; size_t outStart;
size_t outEnd; size_t outEnd;
size_t hPos;
ZBUFF_dStage stage; ZBUFF_dStage stage;
unsigned char headerBuffer[ZSTD_frameHeaderSize_max];
}; /* typedef'd to ZBUFF_DCtx within "zstd_buffered.h" */ }; /* typedef'd to ZBUFF_DCtx within "zstd_buffered.h" */
@ -369,7 +365,7 @@ size_t ZBUFF_freeDCtx(ZBUFF_DCtx* zbc)
size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* zbc, const void* dict, size_t dictSize) size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* zbc, const void* dict, size_t dictSize)
{ {
zbc->stage = ZBUFFds_readHeader; zbc->stage = ZBUFFds_readHeader;
zbc->hPos = zbc->inPos = zbc->outStart = zbc->outEnd = 0; zbc->inPos = zbc->outStart = zbc->outEnd = 0;
return ZSTD_decompressBegin_usingDict(zbc->zc, dict, dictSize); return ZSTD_decompressBegin_usingDict(zbc->zc, dict, dictSize);
} }
@ -381,14 +377,16 @@ size_t ZBUFF_decompressInit(ZBUFF_DCtx* zbc)
/* *** Decompression *** */ /* *** Decompression *** */
size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePtr, const void* src, size_t* srcSizePtr) size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc,
void* dst, size_t* dstCapacityPtr,
const void* src, size_t* srcSizePtr)
{ {
const char* const istart = (const char*)src; const char* const istart = (const char*)src;
const char* ip = istart; const char* ip = istart;
const char* const iend = istart + *srcSizePtr; const char* const iend = istart + *srcSizePtr;
char* const ostart = (char*)dst; char* const ostart = (char*)dst;
char* op = ostart; char* op = ostart;
char* const oend = ostart + *maxDstSizePtr; char* const oend = ostart + *dstCapacityPtr;
U32 notDone = 1; U32 notDone = 1;
while (notDone) { while (notDone) {
@ -399,69 +397,36 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt
case ZBUFFds_readHeader : case ZBUFFds_readHeader :
/* read header from src */ /* read header from src */
{ { size_t const headerSize = ZSTD_getFrameParams(&(zbc->fParams), src, *srcSizePtr);
size_t headerSize = ZSTD_getFrameParams(&(zbc->params), src, *srcSizePtr);
if (ZSTD_isError(headerSize)) return headerSize; if (ZSTD_isError(headerSize)) return headerSize;
if (headerSize) { if (headerSize) {
/* not enough input to decode header : tell how many bytes would be necessary */ /* not enough input to decode header : needs headerSize > *srcSizePtr */
memcpy(zbc->headerBuffer+zbc->hPos, src, *srcSizePtr); *dstCapacityPtr = 0;
zbc->hPos += *srcSizePtr; *srcSizePtr = 0;
*maxDstSizePtr = 0; return headerSize;
zbc->stage = ZBUFFds_loadHeader; } }
return headerSize - zbc->hPos;
}
zbc->stage = ZBUFFds_decodeHeader;
break;
}
case ZBUFFds_loadHeader: /* Frame header provides buffer sizes */
/* complete header from src */ { size_t const neededInSize = ZSTD_BLOCKSIZE_MAX; /* a block is never > ZSTD_BLOCKSIZE_MAX */
if (zbc->inBuffSize < neededInSize) {
free(zbc->inBuff);
zbc->inBuffSize = neededInSize;
zbc->inBuff = (char*)malloc(neededInSize);
if (zbc->inBuff == NULL) return ERROR(memory_allocation);
} }
{ {
size_t headerSize = ZBUFF_limitCopy( size_t const neededOutSize = (size_t)1 << zbc->fParams.windowLog;
zbc->headerBuffer + zbc->hPos, ZSTD_frameHeaderSize_max - zbc->hPos, if (zbc->outBuffSize < neededOutSize) {
src, *srcSizePtr); free(zbc->outBuff);
zbc->hPos += headerSize; zbc->outBuffSize = neededOutSize;
ip += headerSize; zbc->outBuff = (char*)malloc(neededOutSize);
headerSize = ZSTD_getFrameParams(&(zbc->params), zbc->headerBuffer, zbc->hPos); if (zbc->outBuff == NULL) return ERROR(memory_allocation);
if (ZSTD_isError(headerSize)) return headerSize; } }
if (headerSize) { zbc->stage = ZBUFFds_read;
/* not enough input to decode header : tell how many bytes would be necessary */
*maxDstSizePtr = 0;
return headerSize - zbc->hPos;
}
// zbc->stage = ZBUFFds_decodeHeader; break; /* useless : stage follows */
}
case ZBUFFds_decodeHeader:
/* apply header to create / resize buffers */
{
size_t neededOutSize = (size_t)1 << zbc->params.windowLog;
size_t neededInSize = BLOCKSIZE; /* a block is never > BLOCKSIZE */
if (zbc->inBuffSize < neededInSize) {
free(zbc->inBuff);
zbc->inBuffSize = neededInSize;
zbc->inBuff = (char*)malloc(neededInSize);
if (zbc->inBuff == NULL) return ERROR(memory_allocation);
}
if (zbc->outBuffSize < neededOutSize) {
free(zbc->outBuff);
zbc->outBuffSize = neededOutSize;
zbc->outBuff = (char*)malloc(neededOutSize);
if (zbc->outBuff == NULL) return ERROR(memory_allocation);
} }
if (zbc->hPos) {
/* some data already loaded into headerBuffer : transfer into inBuff */
memcpy(zbc->inBuff, zbc->headerBuffer, zbc->hPos);
zbc->inPos = zbc->hPos;
zbc->hPos = 0;
zbc->stage = ZBUFFds_load;
break;
}
zbc->stage = ZBUFFds_read;
case ZBUFFds_read: case ZBUFFds_read:
{ {
size_t neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc); size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc);
if (neededInSize==0) { /* end of frame */ if (neededInSize==0) { /* end of frame */
zbc->stage = ZBUFFds_init; zbc->stage = ZBUFFds_init;
notDone = 0; notDone = 0;
@ -469,7 +434,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt
} }
if ((size_t)(iend-ip) >= neededInSize) { if ((size_t)(iend-ip) >= neededInSize) {
/* directly decode from src */ /* directly decode from src */
size_t decodedSize = ZSTD_decompressContinue(zbc->zc, size_t const decodedSize = ZSTD_decompressContinue(zbc->zc,
zbc->outBuff + zbc->outStart, zbc->outBuffSize - zbc->outStart, zbc->outBuff + zbc->outStart, zbc->outBuffSize - zbc->outStart,
ip, neededInSize); ip, neededInSize);
if (ZSTD_isError(decodedSize)) return decodedSize; if (ZSTD_isError(decodedSize)) return decodedSize;
@ -485,8 +450,8 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt
case ZBUFFds_load: case ZBUFFds_load:
{ {
size_t neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc); size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc);
size_t toLoad = neededInSize - zbc->inPos; /* should always be <= remaining space within inBuff */ size_t const toLoad = neededInSize - zbc->inPos; /* should always be <= remaining space within inBuff */
size_t loadedSize; size_t loadedSize;
if (toLoad > zbc->inBuffSize - zbc->inPos) return ERROR(corruption_detected); /* should never happen */ if (toLoad > zbc->inBuffSize - zbc->inPos) return ERROR(corruption_detected); /* should never happen */
loadedSize = ZBUFF_limitCopy(zbc->inBuff + zbc->inPos, toLoad, ip, iend-ip); loadedSize = ZBUFF_limitCopy(zbc->inBuff + zbc->inPos, toLoad, ip, iend-ip);
@ -494,7 +459,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt
zbc->inPos += loadedSize; zbc->inPos += loadedSize;
if (loadedSize < toLoad) { notDone = 0; break; } /* not enough input, wait for more */ if (loadedSize < toLoad) { notDone = 0; break; } /* not enough input, wait for more */
{ {
size_t decodedSize = ZSTD_decompressContinue(zbc->zc, size_t const decodedSize = ZSTD_decompressContinue(zbc->zc,
zbc->outBuff + zbc->outStart, zbc->outBuffSize - zbc->outStart, zbc->outBuff + zbc->outStart, zbc->outBuffSize - zbc->outStart,
zbc->inBuff, neededInSize); zbc->inBuff, neededInSize);
if (ZSTD_isError(decodedSize)) return decodedSize; if (ZSTD_isError(decodedSize)) return decodedSize;
@ -506,13 +471,13 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt
} } } }
case ZBUFFds_flush: case ZBUFFds_flush:
{ {
size_t toFlushSize = zbc->outEnd - zbc->outStart; size_t const toFlushSize = zbc->outEnd - zbc->outStart;
size_t flushedSize = ZBUFF_limitCopy(op, oend-op, zbc->outBuff + zbc->outStart, toFlushSize); size_t const flushedSize = ZBUFF_limitCopy(op, oend-op, zbc->outBuff + zbc->outStart, toFlushSize);
op += flushedSize; op += flushedSize;
zbc->outStart += flushedSize; zbc->outStart += flushedSize;
if (flushedSize == toFlushSize) { if (flushedSize == toFlushSize) {
zbc->stage = ZBUFFds_read; zbc->stage = ZBUFFds_read;
if (zbc->outStart + BLOCKSIZE > zbc->outBuffSize) if (zbc->outStart + ZSTD_BLOCKSIZE_MAX > zbc->outBuffSize)
zbc->outStart = zbc->outEnd = 0; zbc->outStart = zbc->outEnd = 0;
break; break;
} }
@ -523,12 +488,12 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt
default: return ERROR(GENERIC); /* impossible */ default: return ERROR(GENERIC); /* impossible */
} } } }
/* result */
*srcSizePtr = ip-istart; *srcSizePtr = ip-istart;
*maxDstSizePtr = op-ostart; *dstCapacityPtr = op-ostart;
{ {
size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zbc->zc); size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zbc->zc);
if (nextSrcSizeHint > ZBUFF_blockHeaderSize) nextSrcSizeHint+= ZBUFF_blockHeaderSize; /* get next block header too */ if (nextSrcSizeHint > ZSTD_blockHeaderSize) nextSrcSizeHint+= ZSTD_blockHeaderSize; /* get following block header too */
nextSrcSizeHint -= zbc->inPos; /* already loaded*/ nextSrcSizeHint -= zbc->inPos; /* already loaded*/
return nextSrcSizeHint; return nextSrcSizeHint;
} }
@ -542,7 +507,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt
unsigned ZBUFF_isError(size_t errorCode) { return ERR_isError(errorCode); } unsigned ZBUFF_isError(size_t errorCode) { return ERR_isError(errorCode); }
const char* ZBUFF_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } const char* ZBUFF_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); }
size_t ZBUFF_recommendedCInSize(void) { return BLOCKSIZE; } size_t ZBUFF_recommendedCInSize(void) { return ZSTD_BLOCKSIZE_MAX; }
size_t ZBUFF_recommendedCOutSize(void) { return ZSTD_compressBound(BLOCKSIZE) + ZBUFF_blockHeaderSize + ZBUFF_endFrameSize; } size_t ZBUFF_recommendedCOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + ZBUFF_endFrameSize; }
size_t ZBUFF_recommendedDInSize(void) { return BLOCKSIZE + ZBUFF_blockHeaderSize /* block header size*/ ; } size_t ZBUFF_recommendedDInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize /* block header size*/ ; }
size_t ZBUFF_recommendedDOutSize(void) { return BLOCKSIZE; } size_t ZBUFF_recommendedDOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }

View File

@ -75,7 +75,7 @@ ZSTDLIB_API size_t ZBUFF_compressFlush(ZBUFF_CCtx* cctx, void* dst, size_t* dstC
ZSTDLIB_API size_t ZBUFF_compressEnd(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr); ZSTDLIB_API size_t ZBUFF_compressEnd(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr);
/*-************************************************* /*-*************************************************
* Streaming compression * Streaming compression - howto
* *
* A ZBUFF_CCtx object is required to track streaming operation. * A ZBUFF_CCtx object is required to track streaming operation.
* Use ZBUFF_createCCtx() and ZBUFF_freeCCtx() to create/release resources. * Use ZBUFF_createCCtx() and ZBUFF_freeCCtx() to create/release resources.
@ -127,26 +127,27 @@ ZSTDLIB_API size_t ZBUFF_decompressContinue(ZBUFF_DCtx* dctx,
const void* src, size_t* srcSizePtr); const void* src, size_t* srcSizePtr);
/*-*************************************************************************** /*-***************************************************************************
* Streaming decompression * Streaming decompression howto
* *
* A ZBUFF_DCtx object is required to track streaming operations. * A ZBUFF_DCtx object is required to track streaming operations.
* Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources. * Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources.
* Use ZBUFF_decompressInit() to start a new decompression operation, * Use ZBUFF_decompressInit() to start a new decompression operation,
* or ZBUFF_decompressInitDictionary() if decompression requires a dictionary. * or ZBUFF_decompressInitDictionary() if decompression requires a dictionary.
* Note that ZBUFF_DCtx objects can be reused multiple times. * Note that ZBUFF_DCtx objects can be re-init multiple times.
* *
* Use ZBUFF_decompressContinue() repetitively to consume your input. * Use ZBUFF_decompressContinue() repetitively to consume your input.
* *srcSizePtr and *dstCapacityPtr can be any size. * *srcSizePtr and *dstCapacityPtr can be any size.
* The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr. * The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr.
* Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again. * Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again.
* The content of @dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters or change @dst. * The content of @dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters, or change @dst.
* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to help latency) * @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to help latency),
* or 0 when a frame is completely decoded * or 0 when a frame is completely decoded,
* or an error code, which can be tested using ZBUFF_isError(). * or an error code, which can be tested using ZBUFF_isError().
* *
* Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize() / ZBUFF_recommendedDOutSize() * Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize() and ZBUFF_recommendedDOutSize()
* output : ZBUFF_recommendedDOutSize==128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded. * output : ZBUFF_recommendedDOutSize==128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded.
* input : ZBUFF_recommendedDInSize==128Kb+3; just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . * input : ZBUFF_recommendedDInSize == 128KB + 3;
* just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 .
* *******************************************************************************/ * *******************************************************************************/

View File

@ -587,7 +587,7 @@ typedef struct
{ {
ZSTD_CCtx* ref; ZSTD_CCtx* ref;
ZSTD_CCtx* zc; ZSTD_CCtx* zc;
void* workPlace; /* must be BLOCKSIZE allocated */ void* workPlace; /* must be ZSTD_BLOCKSIZE_MAX allocated */
} EStats_ress_t; } EStats_ress_t;
@ -599,9 +599,9 @@ static void ZDICT_countEStats(EStats_ress_t esr,
const U32* u32Ptr; const U32* u32Ptr;
seqStore_t seqStore; seqStore_t seqStore;
if (srcSize > BLOCKSIZE) srcSize = BLOCKSIZE; /* protection vs large samples */ if (srcSize > ZSTD_BLOCKSIZE_MAX) srcSize = ZSTD_BLOCKSIZE_MAX; /* protection vs large samples */
ZSTD_copyCCtx(esr.zc, esr.ref); ZSTD_copyCCtx(esr.zc, esr.ref);
ZSTD_compressBlock(esr.zc, esr.workPlace, BLOCKSIZE, src, srcSize); ZSTD_compressBlock(esr.zc, esr.workPlace, ZSTD_BLOCKSIZE_MAX, src, srcSize);
seqStore = ZSTD_copySeqStore(esr.zc); seqStore = ZSTD_copySeqStore(esr.zc);
/* count stats */ /* count stats */
@ -654,7 +654,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize,
for (u=0; u<=MaxLL; u++) litlengthCount[u]=1; for (u=0; u<=MaxLL; u++) litlengthCount[u]=1;
esr.ref = ZSTD_createCCtx(); esr.ref = ZSTD_createCCtx();
esr.zc = ZSTD_createCCtx(); esr.zc = ZSTD_createCCtx();
esr.workPlace = malloc(BLOCKSIZE); esr.workPlace = malloc(ZSTD_BLOCKSIZE_MAX);
if (!esr.ref || !esr.zc || !esr.workPlace) { if (!esr.ref || !esr.zc || !esr.workPlace) {
eSize = ERROR(memory_allocation); eSize = ERROR(memory_allocation);
DISPLAYLEVEL(1, "Not enough memory"); DISPLAYLEVEL(1, "Not enough memory");

View File

@ -104,7 +104,7 @@ struct ZSTD_CCtx_s
size_t workSpaceSize; size_t workSpaceSize;
size_t blockSize; size_t blockSize;
size_t hbSize; size_t hbSize;
char headerBuffer[ZSTD_frameHeaderSize_max]; char headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
seqStore_t seqStore; /* sequences storage ptrs */ seqStore_t seqStore; /* sequences storage ptrs */
U32* hashTable; U32* hashTable;
@ -170,7 +170,7 @@ void ZSTD_validateParams(ZSTD_parameters* params)
size_t ZSTD_sizeofCCtx(ZSTD_parameters params) /* hidden interface, for paramagrill */ size_t ZSTD_sizeofCCtx(ZSTD_parameters params) /* hidden interface, for paramagrill */
{ /* copy / pasted from ZSTD_resetCCtx_advanced */ { /* copy / pasted from ZSTD_resetCCtx_advanced */
const size_t blockSize = MIN(BLOCKSIZE, (size_t)1 << params.windowLog); const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.windowLog);
const U32 contentLog = (params.strategy == ZSTD_fast) ? 1 : params.contentLog; const U32 contentLog = (params.strategy == ZSTD_fast) ? 1 : params.contentLog;
const U32 divider = (params.searchLength==3) ? 3 : 4; const U32 divider = (params.searchLength==3) ? 3 : 4;
const size_t maxNbSeq = blockSize / divider; const size_t maxNbSeq = blockSize / divider;
@ -187,7 +187,7 @@ size_t ZSTD_sizeofCCtx(ZSTD_parameters params) /* hidden interface, for parama
static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
ZSTD_parameters params) ZSTD_parameters params)
{ /* note : params considered validated here */ { /* note : params considered validated here */
const size_t blockSize = MIN(BLOCKSIZE, (size_t)1 << params.windowLog); const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.windowLog);
const U32 contentLog = (params.strategy == ZSTD_fast) ? 1 : params.contentLog; const U32 contentLog = (params.strategy == ZSTD_fast) ? 1 : params.contentLog;
const U32 divider = (params.searchLength==3) ? 3 : 4; const U32 divider = (params.searchLength==3) ? 3 : 4;
const size_t maxNbSeq = blockSize / divider; const size_t maxNbSeq = blockSize / divider;
@ -289,7 +289,7 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
} }
/*! ZSTD_reduceIndex /*! ZSTD_reduceIndex() :
* rescale indexes to avoid future overflow (indexes are U32) */ * rescale indexes to avoid future overflow (indexes are U32) */
static void ZSTD_reduceIndex (ZSTD_CCtx* zc, static void ZSTD_reduceIndex (ZSTD_CCtx* zc,
const U32 reducerValue) const U32 reducerValue)
@ -310,6 +310,37 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc,
* Block entropic compression * Block entropic compression
*********************************************************/ *********************************************************/
/* Frame format description
Frame Header - [ Block Header - Block ] - Frame End
1) Frame Header
- 4 bytes - Magic Number : ZSTD_MAGICNUMBER (defined within zstd_static.h)
- 1 byte - Frame Descriptor
2) Block Header
- 3 bytes, starting with a 2-bits descriptor
Uncompressed, Compressed, Frame End, unused
3) Block
See Block Format Description
4) Frame End
- 3 bytes, compatible with Block Header
*/
/* Frame descriptor
1 byte, using :
bit 0-3 : windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN (see zstd_internal.h)
bit 4 : minmatch 4(0) or 3(1)
bit 5 : reserved (must be zero)
bit 6-7 : Frame content size : unknown, 1 byte, 2 bytes, 8 bytes
Optional : content size (0, 1, 2 or 8 bytes)
0 : unknown
1 : 0-255 bytes
2 : 256 - 65535+256
8 : up to 16 exa
*/
/* Block format description /* Block format description
Block = Literal Section - Sequences Section Block = Literal Section - Sequences Section
@ -396,11 +427,11 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc,
FSE_ENCODING_DYNAMIC : read NCount FSE_ENCODING_DYNAMIC : read NCount
*/ */
size_t ZSTD_noCompressBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize) size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
{ {
BYTE* const ostart = (BYTE* const)dst; BYTE* const ostart = (BYTE* const)dst;
if (srcSize + ZSTD_blockHeaderSize > maxDstSize) return ERROR(dstSize_tooSmall); if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize); memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
/* Build header */ /* Build header */
@ -413,12 +444,12 @@ size_t ZSTD_noCompressBlock (void* dst, size_t maxDstSize, const void* src, size
} }
static size_t ZSTD_noCompressLiterals (void* dst, size_t maxDstSize, const void* src, size_t srcSize) static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
{ {
BYTE* const ostart = (BYTE* const)dst; BYTE* const ostart = (BYTE* const)dst;
const U32 flSize = 1 + (srcSize>31) + (srcSize>4095); const U32 flSize = 1 + (srcSize>31) + (srcSize>4095);
if (srcSize + flSize > maxDstSize) return ERROR(dstSize_tooSmall); if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
switch(flSize) switch(flSize)
{ {
@ -441,12 +472,12 @@ static size_t ZSTD_noCompressLiterals (void* dst, size_t maxDstSize, const void*
return srcSize + flSize; return srcSize + flSize;
} }
static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize) static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
{ {
BYTE* const ostart = (BYTE* const)dst; BYTE* const ostart = (BYTE* const)dst;
U32 flSize = 1 + (srcSize>31) + (srcSize>4095); U32 flSize = 1 + (srcSize>31) + (srcSize>4095);
(void)maxDstSize; /* maxDstSize guaranteed to be >=4, hence large enough */ (void)dstCapacity; /* dstCapacity guaranteed to be >=4, hence large enough */
switch(flSize) switch(flSize)
{ {
@ -473,7 +504,7 @@ static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t maxDstSize, const
size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; } size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc, static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
void* dst, size_t maxDstSize, void* dst, size_t dstCapacity,
const void* src, size_t srcSize) const void* src, size_t srcSize)
{ {
const size_t minGain = ZSTD_minGain(srcSize); const size_t minGain = ZSTD_minGain(srcSize);
@ -483,19 +514,19 @@ static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
U32 hType = IS_HUF; U32 hType = IS_HUF;
size_t clitSize; size_t clitSize;
if (maxDstSize < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */ if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
if (zc->flagStaticTables && (lhSize==3)) { if (zc->flagStaticTables && (lhSize==3)) {
hType = IS_PCH; hType = IS_PCH;
singleStream = 1; singleStream = 1;
clitSize = HUF_compress1X_usingCTable(ostart+lhSize, maxDstSize-lhSize, src, srcSize, zc->hufTable); clitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
} else { } else {
clitSize = singleStream ? HUF_compress1X(ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12) clitSize = singleStream ? HUF_compress1X(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12)
: HUF_compress2 (ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12); : HUF_compress2 (ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12);
} }
if ((clitSize==0) || (clitSize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, maxDstSize, src, srcSize); if ((clitSize==0) || (clitSize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
if (clitSize==1) return ZSTD_compressRleLiteralsBlock(dst, maxDstSize, src, srcSize); if (clitSize==1) return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
/* Build header */ /* Build header */
switch(lhSize) switch(lhSize)
@ -528,7 +559,7 @@ static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
#define LITERAL_NOENTROPY 63 /* don't even attempt to compress literals below this threshold (cheap heuristic) */ #define LITERAL_NOENTROPY 63 /* don't even attempt to compress literals below this threshold (cheap heuristic) */
size_t ZSTD_compressSequences(ZSTD_CCtx* zc, size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
void* dst, size_t maxDstSize, void* dst, size_t dstCapacity,
size_t srcSize) size_t srcSize)
{ {
const seqStore_t* seqStorePtr = &(zc->seqStore); const seqStore_t* seqStorePtr = &(zc->seqStore);
@ -548,7 +579,7 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
BYTE* const offCodeTable = seqStorePtr->offCodeStart; BYTE* const offCodeTable = seqStorePtr->offCodeStart;
BYTE* const ostart = (BYTE*)dst; BYTE* const ostart = (BYTE*)dst;
BYTE* op = ostart; BYTE* op = ostart;
BYTE* const oend = ostart + maxDstSize; BYTE* const oend = ostart + dstCapacity;
const size_t nbSeq = llPtr - llTable; const size_t nbSeq = llPtr - llTable;
const size_t minGain = ZSTD_minGain(srcSize); const size_t minGain = ZSTD_minGain(srcSize);
const size_t maxCSize = srcSize - minGain; const size_t maxCSize = srcSize - minGain;
@ -561,9 +592,9 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
const size_t minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY; const size_t minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
if (litSize <= minLitSize) if (litSize <= minLitSize)
cSize = ZSTD_noCompressLiterals(op, maxDstSize, op_lit_start, litSize); cSize = ZSTD_noCompressLiterals(op, dstCapacity, op_lit_start, litSize);
else else
cSize = ZSTD_compressLiterals(zc, op, maxDstSize, op_lit_start, litSize); cSize = ZSTD_compressLiterals(zc, op, dstCapacity, op_lit_start, litSize);
if (ZSTD_isError(cSize)) return cSize; if (ZSTD_isError(cSize)) return cSize;
op += cSize; op += cSize;
} }
@ -1951,17 +1982,17 @@ static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int
} }
static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize) static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
{ {
ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit); ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit);
if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */ if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */
blockCompressor(zc, src, srcSize); blockCompressor(zc, src, srcSize);
return ZSTD_compressSequences(zc, dst, maxDstSize, srcSize); return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
} }
static size_t ZSTD_compress_generic (ZSTD_CCtx* zc, static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
void* dst, size_t maxDstSize, void* dst, size_t dstCapacity,
const void* src, size_t srcSize) const void* src, size_t srcSize)
{ {
size_t blockSize = zc->blockSize; size_t blockSize = zc->blockSize;
@ -1980,7 +2011,7 @@ static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
while (remaining) { while (remaining) {
size_t cSize; size_t cSize;
if (maxDstSize < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */ if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
if (remaining < blockSize) blockSize = remaining; if (remaining < blockSize) blockSize = remaining;
if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) { /* enforce maxDist */ if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) { /* enforce maxDist */
@ -1989,11 +2020,11 @@ static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit; if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit;
} }
cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, maxDstSize-ZSTD_blockHeaderSize, ip, blockSize); cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
if (ZSTD_isError(cSize)) return cSize; if (ZSTD_isError(cSize)) return cSize;
if (cSize == 0) { /* block is not compressible */ if (cSize == 0) { /* block is not compressible */
cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize); cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize);
if (ZSTD_isError(cSize)) return cSize; if (ZSTD_isError(cSize)) return cSize;
} else { } else {
op[0] = (BYTE)(cSize>>16); op[0] = (BYTE)(cSize>>16);
@ -2004,7 +2035,7 @@ static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
} }
remaining -= blockSize; remaining -= blockSize;
maxDstSize -= cSize; dstCapacity -= cSize;
ip += blockSize; ip += blockSize;
op += cSize; op += cSize;
} }
@ -2088,12 +2119,12 @@ size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
} }
size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize) size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
{ {
if (srcSize > BLOCKSIZE) return ERROR(srcSize_wrong); if (srcSize > ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);
zc->params.searchLength = MINMATCH; /* force ZSTD_btopt to MINMATCH in block mode */ zc->params.searchLength = MINMATCH; /* force ZSTD_btopt to MINMATCH in block mode */
ZSTD_LOG_BLOCK("%p: ZSTD_compressBlock searchLength=%d\n", zc->base, zc->params.searchLength); ZSTD_LOG_BLOCK("%p: ZSTD_compressBlock searchLength=%d\n", zc->base, zc->params.searchLength);
return ZSTD_compressContinue_internal(zc, dst, maxDstSize, src, srcSize, 0); return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 0);
} }
@ -2141,10 +2172,10 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t
/* Dictionary format : /* Dictionary format :
Magic == ZSTD_DICT_MAGIC (4 bytes) Magic == ZSTD_DICT_MAGIC (4 bytes)
Huff0 CTable (256 * 4 bytes) => to be changed to read from writeCTable HUF_writeCTable(256)
Dictionary content Dictionary content
*/ */
/*! ZSTD_loadDictEntropyStats /*! ZSTD_loadDictEntropyStats() :
@return : size read from dictionary */ @return : size read from dictionary */
static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize) static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
{ {
@ -2185,49 +2216,66 @@ static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t
return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize; return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize;
} }
/** ZSTD_compress_insertDictionary() :
* @return : 0, or an error code */
static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize) static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
{ {
if (dict && (dictSize>4)) { if ((dict==NULL) || (dictSize<=4)) return 0;
U32 magic = MEM_readLE32(dict);
size_t eSize;
if (magic != ZSTD_DICT_MAGIC)
return ZSTD_loadDictionaryContent(zc, dict, dictSize);
eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4, dictSize-4) + 4; /* default : dict is pure content */
if (ZSTD_isError(eSize)) return eSize; if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize);
return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
/* known magic number : dict is parsed for entropy stats and content */
{ size_t const eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4 /* skip magic */, dictSize-4) + 4;
if (ZSTD_isError(eSize)) return eSize;
return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
} }
return 0;
} }
/*! ZSTD_compressBegin_advanced /*! ZSTD_compressBegin_advanced() :
* @return : 0, or an error code */ * @return : 0, or an error code */
size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc, size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc,
const void* dict, size_t dictSize, const void* dict, size_t dictSize,
ZSTD_parameters params) ZSTD_parameters params)
{ {
size_t errorCode;
ZSTD_validateParams(&params); ZSTD_validateParams(&params);
errorCode = ZSTD_resetCCtx_advanced(zc, params); { size_t const errorCode = ZSTD_resetCCtx_advanced(zc, params);
if (ZSTD_isError(errorCode)) return errorCode; if (ZSTD_isError(errorCode)) return errorCode; }
/* Write Frame Header into ctx headerBuffer */
MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER);
{
BYTE* const op = (BYTE*)zc->headerBuffer;
U32 const fcsSize[4] = { 0, 1, 2, 8 };
U32 const fcsId = (params.srcSize>0) + (params.srcSize>=256) + (params.srcSize>=65536+256); /* 0-3 */
BYTE fdescriptor = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN); /* windowLog : 4 KB - 128 MB */
fdescriptor |= (BYTE)((params.searchLength==3)<<4); /* mml : 3-4 */
fdescriptor |= (BYTE)(fcsId << 6);
op[4] = fdescriptor;
switch(fcsId)
{
default: /* impossible */
case 0 : break;
case 1 : op[5] = (BYTE)(params.srcSize); break;
case 2 : MEM_writeLE16(op+5, (U16)(params.srcSize-256)); break;
case 3 : MEM_writeLE64(op+5, (U64)(params.srcSize)); break;
}
zc->hbSize = ZSTD_frameHeaderSize_min + fcsSize[fcsId];
}
MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER); /* Write Header */
((BYTE*)zc->headerBuffer)[4] = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN + ((params.searchLength==3)<<4));
zc->hbSize = ZSTD_frameHeaderSize_min;
zc->stage = 0; zc->stage = 0;
return ZSTD_compress_insertDictionary(zc, dict, dictSize); return ZSTD_compress_insertDictionary(zc, dict, dictSize);
} }
size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel) size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel)
{ {
ZSTD_parameters params = ZSTD_getParams(compressionLevel, dictSize);
params.srcSize = 0;
ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_usingDict compressionLevel=%d\n", zc->base, compressionLevel); ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_usingDict compressionLevel=%d\n", zc->base, compressionLevel);
return ZSTD_compressBegin_advanced(zc, dict, dictSize, ZSTD_getParams(compressionLevel, MAX(128 KB, dictSize))); return ZSTD_compressBegin_advanced(zc, dict, dictSize, params);
} }
size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel) size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
@ -2237,10 +2285,10 @@ size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
} }
/*! ZSTD_compressEnd /*! ZSTD_compressEnd() :
* Write frame epilogue * Write frame epilogue.
* @return : nb of bytes written into dst (or an error code) */ * @return : nb of bytes written into dst (or an error code) */
size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize) size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t dstCapacity)
{ {
BYTE* op = (BYTE*)dst; BYTE* op = (BYTE*)dst;
size_t hbSize = 0; size_t hbSize = 0;
@ -2248,15 +2296,15 @@ size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize)
/* empty frame */ /* empty frame */
if (zc->stage==0) { if (zc->stage==0) {
hbSize = zc->hbSize; hbSize = zc->hbSize;
if (maxDstSize <= hbSize) return ERROR(dstSize_tooSmall); if (dstCapacity <= hbSize) return ERROR(dstSize_tooSmall);
zc->stage = 1; zc->stage = 1;
memcpy(dst, zc->headerBuffer, hbSize); memcpy(dst, zc->headerBuffer, hbSize);
maxDstSize -= hbSize; dstCapacity -= hbSize;
op += hbSize; op += hbSize;
} }
/* frame epilogue */ /* frame epilogue */
if (maxDstSize < 3) return ERROR(dstSize_tooSmall); if (dstCapacity < 3) return ERROR(dstSize_tooSmall);
op[0] = (BYTE)(bt_end << 6); op[0] = (BYTE)(bt_end << 6);
op[1] = 0; op[1] = 0;
op[2] = 0; op[2] = 0;
@ -2266,16 +2314,16 @@ size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize)
size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
void* dst, size_t maxDstSize, void* dst, size_t dstCapacity,
const void* src, size_t srcSize) const void* src, size_t srcSize)
{ {
size_t outSize; size_t outSize;
size_t errorCode = ZSTD_copyCCtx(cctx, preparedCCtx); size_t errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
if (ZSTD_isError(errorCode)) return errorCode; if (ZSTD_isError(errorCode)) return errorCode;
errorCode = ZSTD_compressContinue(cctx, dst, maxDstSize, src, srcSize); errorCode = ZSTD_compressContinue(cctx, dst, dstCapacity, src, srcSize);
if (ZSTD_isError(errorCode)) return errorCode; if (ZSTD_isError(errorCode)) return errorCode;
outSize = errorCode; outSize = errorCode;
errorCode = ZSTD_compressEnd(cctx, (char*)dst+outSize, maxDstSize-outSize); errorCode = ZSTD_compressEnd(cctx, (char*)dst+outSize, dstCapacity-outSize);
if (ZSTD_isError(errorCode)) return errorCode; if (ZSTD_isError(errorCode)) return errorCode;
outSize += errorCode; outSize += errorCode;
return outSize; return outSize;
@ -2283,51 +2331,50 @@ size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* prepare
size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
void* dst, size_t maxDstSize, void* dst, size_t dstCapacity,
const void* src, size_t srcSize, const void* src, size_t srcSize,
const void* dict,size_t dictSize, const void* dict,size_t dictSize,
ZSTD_parameters params) ZSTD_parameters params)
{ {
BYTE* const ostart = (BYTE*)dst; BYTE* const ostart = (BYTE*)dst;
BYTE* op = ostart; BYTE* op = ostart;
size_t oSize;
/* Init */ /* Init */
oSize = ZSTD_compressBegin_advanced(ctx, dict, dictSize, params); { size_t const errorCode = ZSTD_compressBegin_advanced(ctx, dict, dictSize, params);
if(ZSTD_isError(oSize)) return oSize; if(ZSTD_isError(errorCode)) return errorCode; }
/* body (compression) */ /* body (compression) */
oSize = ZSTD_compressContinue (ctx, op, maxDstSize, src, srcSize); { size_t const oSize = ZSTD_compressContinue (ctx, op, dstCapacity, src, srcSize);
if(ZSTD_isError(oSize)) return oSize; if(ZSTD_isError(oSize)) return oSize;
op += oSize; op += oSize;
maxDstSize -= oSize; dstCapacity -= oSize; }
/* Close frame */ /* Close frame */
oSize = ZSTD_compressEnd(ctx, op, maxDstSize); { size_t const oSize = ZSTD_compressEnd(ctx, op, dstCapacity);
if(ZSTD_isError(oSize)) return oSize; if(ZSTD_isError(oSize)) return oSize;
op += oSize; op += oSize; }
return (op - ostart); return (op - ostart);
} }
size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, 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_LOG_BLOCK("%p: ZSTD_compress_usingDict srcSize=%d dictSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, (int)dictSize, compressionLevel); ZSTD_LOG_BLOCK("%p: ZSTD_compress_usingDict srcSize=%d dictSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, (int)dictSize, compressionLevel);
return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize)); return ZSTD_compress_advanced(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize));
} }
size_t ZSTD_compressCCtx (ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel) size_t ZSTD_compressCCtx (ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
{ {
ZSTD_LOG_BLOCK("%p: ZSTD_compressCCtx srcSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, compressionLevel); ZSTD_LOG_BLOCK("%p: ZSTD_compressCCtx srcSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, compressionLevel);
return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, NULL, 0, ZSTD_getParams(compressionLevel, srcSize)); return ZSTD_compress_advanced(ctx, dst, dstCapacity, src, srcSize, NULL, 0, ZSTD_getParams(compressionLevel, srcSize));
} }
size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel) size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
{ {
size_t result; size_t result;
ZSTD_CCtx ctxBody; ZSTD_CCtx ctxBody;
memset(&ctxBody, 0, sizeof(ctxBody)); memset(&ctxBody, 0, sizeof(ctxBody));
result = ZSTD_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel); result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
free(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */ free(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
return result; return result;
} }

View File

@ -94,13 +94,13 @@ typedef struct
} blockProperties_t; } blockProperties_t;
/* ******************************************************* /*_*******************************************************
* Memory operations * Memory operations
**********************************************************/ **********************************************************/
static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); } static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); }
/* ************************************* /*-*************************************
* Error Management * Error Management
***************************************/ ***************************************/
unsigned ZSTD_versionNumber (void) { return ZSTD_VERSION_NUMBER; } unsigned ZSTD_versionNumber (void) { return ZSTD_VERSION_NUMBER; }
@ -118,7 +118,7 @@ ZSTD_ErrorCode ZSTD_getError(size_t code) { return ERR_getError(code); }
const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); } const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); }
/* ************************************************************* /*-*************************************************************
* Context management * Context management
***************************************************************/ ***************************************************************/
typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader,
@ -136,15 +136,15 @@ struct ZSTD_DCtx_s
const void* dictEnd; const void* dictEnd;
size_t expected; size_t expected;
size_t headerSize; size_t headerSize;
ZSTD_parameters params; ZSTD_frameParams fParams;
blockType_t bType; /* used in ZSTD_decompressContinue(), to transfer blockType between header decoding and block decoding stages */ blockType_t bType; /* used in ZSTD_decompressContinue(), to transfer blockType between header decoding and block decoding stages */
ZSTD_dStage stage; ZSTD_dStage stage;
U32 flagStaticTables; U32 flagStaticTables;
const BYTE* litPtr; const BYTE* litPtr;
size_t litBufSize; size_t litBufSize;
size_t litSize; size_t litSize;
BYTE litBuffer[BLOCKSIZE + WILDCOPY_OVERLENGTH]; BYTE litBuffer[ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH];
BYTE headerBuffer[ZSTD_frameHeaderSize_max]; BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
}; /* typedef'd to ZSTD_DCtx within "zstd_static.h" */ }; /* typedef'd to ZSTD_DCtx within "zstd_static.h" */
size_t sizeofDCtx (void) { return sizeof(ZSTD_DCtx); } size_t sizeofDCtx (void) { return sizeof(ZSTD_DCtx); }
@ -159,7 +159,7 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
dctx->dictEnd = NULL; dctx->dictEnd = NULL;
dctx->hufTableX4[0] = HufLog; dctx->hufTableX4[0] = HufLog;
dctx->flagStaticTables = 0; dctx->flagStaticTables = 0;
dctx->params.searchLength = MINMATCH; /* overwritten by frame but forces ZSTD_btopt to MINMATCH in block mode */ dctx->fParams.mml = MINMATCH; /* overwritten by frame but forces ZSTD_btopt to MINMATCH in block mode */
ZSTD_LOG_BLOCK("%p: ZSTD_decompressBegin searchLength=%d\n", dctx->base, dctx->params.searchLength); ZSTD_LOG_BLOCK("%p: ZSTD_decompressBegin searchLength=%d\n", dctx->base, dctx->params.searchLength);
return 0; return 0;
} }
@ -181,19 +181,19 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
{ {
memcpy(dstDCtx, srcDCtx, memcpy(dstDCtx, srcDCtx,
sizeof(ZSTD_DCtx) - (BLOCKSIZE+WILDCOPY_OVERLENGTH + ZSTD_frameHeaderSize_max)); /* no need to copy workspace */ sizeof(ZSTD_DCtx) - (ZSTD_BLOCKSIZE_MAX+WILDCOPY_OVERLENGTH + ZSTD_frameHeaderSize_max)); /* no need to copy workspace */
} }
/* ************************************************************* /*-*************************************************************
* Decompression section * Decompression section
***************************************************************/ ***************************************************************/
/* Frame format description /* Frame format description
Frame Header - [ Block Header - Block ] - Frame End Frame Header - [ Block Header - Block ] - Frame End
1) Frame Header 1) Frame Header
- 4 bytes - Magic Number : ZSTD_MAGICNUMBER (defined within zstd_internal.h) - 4 bytes - Magic Number : ZSTD_MAGICNUMBER (defined within zstd_static.h)
- 1 byte - Window Descriptor - 1 byte - Frame Descriptor
2) Block Header 2) Block Header
- 3 bytes, starting with a 2-bits descriptor - 3 bytes, starting with a 2-bits descriptor
Uncompressed, Compressed, Frame End, unused Uncompressed, Compressed, Frame End, unused
@ -203,7 +203,24 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
- 3 bytes, compatible with Block Header - 3 bytes, compatible with Block Header
*/ */
/* Block format description
/* Frame descriptor
1 byte, using :
bit 0-3 : windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN (see zstd_internal.h)
bit 4 : minmatch 4(0) or 3(1)
bit 5 : reserved (must be zero)
bit 6-7 : Frame content size : unknown, 1 byte, 2 bytes, 8 bytes
Optional : content size (0, 1, 2 or 8 bytes)
0 : unknown
1 : 0-255 bytes
2 : 256 - 65535+256
8 : up to 16 exa
*/
/* Compressed Block, format description
Block = Literal Section - Sequences Section Block = Literal Section - Sequences Section
Prerequisite : size of (compressed) block, maximum size of regenerated data Prerequisite : size of (compressed) block, maximum size of regenerated data
@ -269,47 +286,60 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
TO DO TO DO
*/ */
static const size_t ZSTD_fcs_fieldSize[4] = { 0, 1, 2, 8 };
/** ZSTD_decodeFrameHeader_Part1() : /** ZSTD_frameHeaderSize() :
* decode the 1st part of the Frame Header, which tells Frame Header size. * srcSize must be >= ZSTD_frameHeaderSize_min.
* srcSize must be == ZSTD_frameHeaderSize_min. * @return : size of the Frame Header */
* @return : the full size of the Frame Header */ static size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
static size_t ZSTD_decodeFrameHeader_Part1(ZSTD_DCtx* zc, const void* src, size_t srcSize)
{ {
U32 magicNumber; U32 fcsId;
if (srcSize != ZSTD_frameHeaderSize_min) if (srcSize < ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong);
return ERROR(srcSize_wrong); fcsId = (((const BYTE*)src)[4]) >> 6;
magicNumber = MEM_readLE32(src); return ZSTD_frameHeaderSize_min + ZSTD_fcs_fieldSize[fcsId];
if (magicNumber != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown);
zc->headerSize = ZSTD_frameHeaderSize_min;
return zc->headerSize;
} }
size_t ZSTD_getFrameParams(ZSTD_parameters* params, const void* src, size_t srcSize) /** ZSTD_getFrameParams() :
* decode Frame Header, or provide expected `srcSize`.
* @return : 0, `fparamsPtr` 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_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize)
{ {
U32 magicNumber; const BYTE* ip = (const BYTE*)src;
if (srcSize < ZSTD_frameHeaderSize_min) return ZSTD_frameHeaderSize_max;
magicNumber = MEM_readLE32(src); if (srcSize < ZSTD_frameHeaderSize_min) return ZSTD_frameHeaderSize_min;
if (magicNumber != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown); if (MEM_readLE32(src) != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown);
memset(params, 0, sizeof(*params));
params->windowLog = (((const BYTE*)src)[4] & 15) + ZSTD_WINDOWLOG_ABSOLUTEMIN; /* ensure there is enough `srcSize` to fully read/decode frame header */
params->searchLength = (((const BYTE*)src)[4] & 16) ? MINMATCH-1 : MINMATCH; { size_t const fhsize = ZSTD_frameHeaderSize(src, srcSize);
if ((((const BYTE*)src)[4] >> 5) != 0) return ERROR(frameParameter_unsupported); /* reserved 3 bits */ if (srcSize < fhsize) return fhsize; }
memset(fparamsPtr, 0, sizeof(*fparamsPtr));
{ BYTE const frameDesc = ip[4];
fparamsPtr->windowLog = (frameDesc & 0xF) + ZSTD_WINDOWLOG_ABSOLUTEMIN;
fparamsPtr->mml = (frameDesc & 0x10) ? MINMATCH-1 : MINMATCH;
if ((frameDesc & 0x20) != 0) return ERROR(frameParameter_unsupported); /* reserved 1 bit */
switch(frameDesc >> 6) /* fcsId */
{
default: /* impossible */
case 0 : fparamsPtr->frameContentSize = 0; break;
case 1 : fparamsPtr->frameContentSize = ip[5]; break;
case 2 : fparamsPtr->frameContentSize = MEM_readLE16(ip+5)+256; break;
case 3 : fparamsPtr->frameContentSize = MEM_readLE64(ip+5); break;
} }
return 0; return 0;
} }
/** ZSTD_decodeFrameHeader_Part2() :
* decode the full Frame Header. /** ZSTD_decodeFrameHeader() :
* srcSize must be the size provided by ZSTD_decodeFrameHeader_Part1(). * `srcSize` must be the size provided by ZSTD_frameHeaderSize().
* @return : 0, or an error code, which can be tested using ZSTD_isError() */ * @return : 0, or an error code, which can be tested using ZSTD_isError() */
static size_t ZSTD_decodeFrameHeader_Part2(ZSTD_DCtx* zc, const void* src, size_t srcSize) static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* zc, const void* src, size_t srcSize)
{ {
size_t result; size_t result = ZSTD_getFrameParams(&(zc->fParams), src, srcSize);
if (srcSize != zc->headerSize) if ((MEM_32bits()) && (zc->fParams.windowLog > 25)) return ERROR(frameParameter_unsupportedBy32bits);
return ERROR(srcSize_wrong);
result = ZSTD_getFrameParams(&(zc->params), src, srcSize);
if ((MEM_32bits()) && (zc->params.windowLog > 25)) return ERROR(frameParameter_unsupportedBy32bits);
return result; return result;
} }
@ -381,7 +411,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
litCSize = ((istart[2] & 3) << 16) + (istart[3] << 8) + istart[4]; litCSize = ((istart[2] & 3) << 16) + (istart[3] << 8) + istart[4];
break; break;
} }
if (litSize > BLOCKSIZE) return ERROR(corruption_detected); if (litSize > ZSTD_BLOCKSIZE_MAX) return ERROR(corruption_detected);
if (HUF_isError(singleStream ? if (HUF_isError(singleStream ?
HUF_decompress1X2(dctx->litBuffer, litSize, istart+lhSize, litCSize) : HUF_decompress1X2(dctx->litBuffer, litSize, istart+lhSize, litCSize) :
@ -389,7 +419,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
return ERROR(corruption_detected); return ERROR(corruption_detected);
dctx->litPtr = dctx->litBuffer; dctx->litPtr = dctx->litBuffer;
dctx->litBufSize = BLOCKSIZE+8; dctx->litBufSize = ZSTD_BLOCKSIZE_MAX+8;
dctx->litSize = litSize; dctx->litSize = litSize;
return litCSize + lhSize; return litCSize + lhSize;
} }
@ -412,7 +442,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
if (HUF_isError(errorCode)) return ERROR(corruption_detected); if (HUF_isError(errorCode)) return ERROR(corruption_detected);
dctx->litPtr = dctx->litBuffer; dctx->litPtr = dctx->litBuffer;
dctx->litBufSize = BLOCKSIZE+WILDCOPY_OVERLENGTH; dctx->litBufSize = ZSTD_BLOCKSIZE_MAX+WILDCOPY_OVERLENGTH;
dctx->litSize = litSize; dctx->litSize = litSize;
return litCSize + lhSize; return litCSize + lhSize;
} }
@ -438,7 +468,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
if (litSize+lhSize > srcSize) return ERROR(corruption_detected); if (litSize+lhSize > srcSize) return ERROR(corruption_detected);
memcpy(dctx->litBuffer, istart+lhSize, litSize); memcpy(dctx->litBuffer, istart+lhSize, litSize);
dctx->litPtr = dctx->litBuffer; dctx->litPtr = dctx->litBuffer;
dctx->litBufSize = BLOCKSIZE+8; dctx->litBufSize = ZSTD_BLOCKSIZE_MAX+8;
dctx->litSize = litSize; dctx->litSize = litSize;
return lhSize+litSize; return lhSize+litSize;
} }
@ -465,10 +495,10 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
litSize = ((istart[0] & 15) << 16) + (istart[1] << 8) + istart[2]; litSize = ((istart[0] & 15) << 16) + (istart[1] << 8) + istart[2];
break; break;
} }
if (litSize > BLOCKSIZE) return ERROR(corruption_detected); if (litSize > ZSTD_BLOCKSIZE_MAX) return ERROR(corruption_detected);
memset(dctx->litBuffer, istart[lhSize], litSize); memset(dctx->litBuffer, istart[lhSize], litSize);
dctx->litPtr = dctx->litBuffer; dctx->litPtr = dctx->litBuffer;
dctx->litBufSize = BLOCKSIZE+WILDCOPY_OVERLENGTH; dctx->litBufSize = ZSTD_BLOCKSIZE_MAX+WILDCOPY_OVERLENGTH;
dctx->litSize = litSize; dctx->litSize = litSize;
return lhSize+1; return lhSize+1;
} }
@ -622,16 +652,14 @@ typedef struct {
static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState, const U32 mls) static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState, const U32 mls)
{ {
size_t litLength;
size_t offset;
size_t matchLength;
const BYTE* dumps = seqState->dumps; const BYTE* dumps = seqState->dumps;
const BYTE* const de = seqState->dumpsEnd; const BYTE* const de = seqState->dumpsEnd;
size_t litLength, offset;
/* Literal length */ /* Literal length */
litLength = FSE_peakSymbol(&(seqState->stateLL)); litLength = FSE_peakSymbol(&(seqState->stateLL));
if (litLength == MaxLL) { if (litLength == MaxLL) {
U32 add = *dumps++; const U32 add = *dumps++;
if (add < 255) litLength += add; if (add < 255) litLength += add;
else { else {
litLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no risk : dumps is always followed by seq tables > 1 byte */ litLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no risk : dumps is always followed by seq tables > 1 byte */
@ -647,9 +675,8 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState, const U32 mls)
1 /*fake*/, 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100, 1 /*fake*/, 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100,
0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000,
0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000, 0x2000000, 0x4000000, /*fake*/ 1, 1, 1, 1 }; 0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000, 0x2000000, 0x4000000, /*fake*/ 1, 1, 1, 1 };
U32 offsetCode = FSE_peakSymbol(&(seqState->stateOffb)); /* <= maxOff, by table construction */ const U32 offsetCode = FSE_peakSymbol(&(seqState->stateOffb)); /* <= maxOff, by table construction */
U32 nbBits = offsetCode - 1; const U32 nbBits = offsetCode ? offsetCode-1 : 0;
if (offsetCode==0) nbBits = 0; /* cmove */
offset = offsetPrefix[offsetCode] + BIT_readBits(&(seqState->DStream), nbBits); offset = offsetPrefix[offsetCode] + BIT_readBits(&(seqState->DStream), nbBits);
if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream)); if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream));
#if ZSTD_REP_NUM == 4 #if ZSTD_REP_NUM == 4
@ -715,23 +742,25 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState, const U32 mls)
if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream)); if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream));
/* MatchLength */ /* MatchLength */
matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); {
if (matchLength == MaxML) { size_t matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream));
U32 add = *dumps++; if (matchLength == MaxML) {
if (add < 255) matchLength += add; const U32 add = *dumps++;
else { if (add < 255) matchLength += add;
matchLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no pb : dumps is always followed by seq tables > 1 byte */ else {
if (matchLength&1) matchLength>>=1, dumps += 3; matchLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no pb : dumps is always followed by seq tables > 1 byte */
else matchLength = (U16)(matchLength)>>1, dumps += 2; if (matchLength&1) matchLength>>=1, dumps += 3;
else matchLength = (U16)(matchLength)>>1, dumps += 2;
}
if (dumps >= de) dumps = de-1; /* late correction, to avoid read overflow (data is now corrupted anyway) */
} }
if (dumps >= de) dumps = de-1; /* late correction, to avoid read overflow (data is now corrupted anyway) */ matchLength += mls;
seq->matchLength = matchLength;
} }
matchLength += mls;
/* save result */ /* save result */
seq->litLength = litLength; seq->litLength = litLength;
seq->offset = offset; seq->offset = offset;
seq->matchLength = matchLength;
seqState->dumps = dumps; seqState->dumps = dumps;
#if 0 /* debug */ #if 0 /* debug */
@ -841,7 +870,7 @@ static size_t ZSTD_decompressSequences(
const BYTE* const base = (const BYTE*) (dctx->base); const BYTE* const base = (const BYTE*) (dctx->base);
const BYTE* const vBase = (const BYTE*) (dctx->vBase); const BYTE* const vBase = (const BYTE*) (dctx->vBase);
const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
const U32 mls = dctx->params.searchLength; const U32 mls = dctx->fParams.mml;
/* Build Decoding Tables */ /* Build Decoding Tables */
errorCode = ZSTD_decodeSeqHeaders(&nbSeq, &dumps, &dumpsLength, errorCode = ZSTD_decodeSeqHeaders(&nbSeq, &dumps, &dumpsLength,
@ -912,7 +941,7 @@ static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
const BYTE* ip = (const BYTE*)src; const BYTE* ip = (const BYTE*)src;
size_t litCSize; size_t litCSize;
if (srcSize >= BLOCKSIZE) return ERROR(srcSize_wrong); if (srcSize >= ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);
ZSTD_LOG_BLOCK("%p: ZSTD_decompressBlock_internal searchLength=%d\n", dctx->base, dctx->params.searchLength); ZSTD_LOG_BLOCK("%p: ZSTD_decompressBlock_internal searchLength=%d\n", dctx->base, dctx->params.searchLength);
@ -935,9 +964,9 @@ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx,
} }
/*! ZSTD_decompress_continueDCtx /*! ZSTD_decompress_continueDCtx() :
* dctx must have been properly initialized */ * `dctx` must have been properly initialized */
static size_t ZSTD_decompress_continueDCtx(ZSTD_DCtx* dctx, static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
void* dst, size_t maxDstSize, void* dst, size_t maxDstSize,
const void* src, size_t srcSize) const void* src, size_t srcSize)
{ {
@ -951,7 +980,7 @@ static size_t ZSTD_decompress_continueDCtx(ZSTD_DCtx* dctx,
/* Frame Header */ /* Frame Header */
{ {
size_t frameHeaderSize; size_t frameHeaderSize, errorCode;
if (srcSize < ZSTD_frameHeaderSize_min+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); if (srcSize < ZSTD_frameHeaderSize_min+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong);
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1) #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1)
{ {
@ -960,12 +989,12 @@ static size_t ZSTD_decompress_continueDCtx(ZSTD_DCtx* dctx,
return ZSTD_decompressLegacy(dst, maxDstSize, src, srcSize, magicNumber); return ZSTD_decompressLegacy(dst, maxDstSize, src, srcSize, magicNumber);
} }
#endif #endif
frameHeaderSize = ZSTD_decodeFrameHeader_Part1(dctx, src, ZSTD_frameHeaderSize_min); frameHeaderSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_min);
if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;
if (srcSize < frameHeaderSize+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); if (srcSize < frameHeaderSize+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong);
errorCode = ZSTD_decodeFrameHeader(dctx, src, frameHeaderSize);
if (ZSTD_isError(errorCode)) return errorCode;
ip += frameHeaderSize; remainingSize -= frameHeaderSize; ip += frameHeaderSize; remainingSize -= frameHeaderSize;
frameHeaderSize = ZSTD_decodeFrameHeader_Part2(dctx, src, frameHeaderSize);
if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;
} }
/* Loop on each block */ /* Loop on each block */
@ -1015,7 +1044,7 @@ size_t ZSTD_decompress_usingPreparedDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* refDC
{ {
ZSTD_copyDCtx(dctx, refDCtx); ZSTD_copyDCtx(dctx, refDCtx);
ZSTD_checkContinuity(dctx, dst); ZSTD_checkContinuity(dctx, dst);
return ZSTD_decompress_continueDCtx(dctx, dst, maxDstSize, src, srcSize); return ZSTD_decompressFrame(dctx, dst, maxDstSize, src, srcSize);
} }
@ -1027,7 +1056,7 @@ size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,
ZSTD_decompressBegin_usingDict(dctx, dict, dictSize); ZSTD_decompressBegin_usingDict(dctx, dict, dictSize);
ZSTD_LOG_BLOCK("%p: ZSTD_decompressBegin_usingDict searchLength=%d\n", dctx->base, dctx->params.searchLength); ZSTD_LOG_BLOCK("%p: ZSTD_decompressBegin_usingDict searchLength=%d\n", dctx->base, dctx->params.searchLength);
ZSTD_checkContinuity(dctx, dst); ZSTD_checkContinuity(dctx, dst);
return ZSTD_decompress_continueDCtx(dctx, dst, maxDstSize, src, srcSize); return ZSTD_decompressFrame(dctx, dst, maxDstSize, src, srcSize);
} }
@ -1036,6 +1065,7 @@ size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const
return ZSTD_decompress_usingDict(dctx, dst, maxDstSize, src, srcSize, NULL, 0); return ZSTD_decompress_usingDict(dctx, dst, maxDstSize, src, srcSize, NULL, 0);
} }
size_t ZSTD_decompress(void* dst, size_t maxDstSize, const void* src, size_t srcSize) size_t ZSTD_decompress(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
{ {
#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE==1) #if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE==1)
@ -1052,7 +1082,7 @@ size_t ZSTD_decompress(void* dst, size_t maxDstSize, const void* src, size_t src
} }
/* ****************************** /*_******************************
* Streaming Decompression API * Streaming Decompression API
********************************/ ********************************/
size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx)
@ -1073,7 +1103,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, co
{ {
/* get frame header size */ /* get frame header size */
if (srcSize != ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong); /* impossible */ if (srcSize != ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong); /* impossible */
dctx->headerSize = ZSTD_decodeFrameHeader_Part1(dctx, src, ZSTD_frameHeaderSize_min); dctx->headerSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_min);
if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;
memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_min); memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_min);
if (dctx->headerSize > ZSTD_frameHeaderSize_min) { if (dctx->headerSize > ZSTD_frameHeaderSize_min) {
@ -1088,7 +1118,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, co
/* get frame header */ /* get frame header */
size_t result; size_t result;
memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_min, src, dctx->expected); memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_min, src, dctx->expected);
result = ZSTD_decodeFrameHeader_Part2(dctx, dctx->headerBuffer, dctx->headerSize); result = ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize);
if (ZSTD_isError(result)) return result; if (ZSTD_isError(result)) return result;
dctx->expected = ZSTD_blockHeaderSize; dctx->expected = ZSTD_blockHeaderSize;
dctx->stage = ZSTDds_decodeBlockHeader; dctx->stage = ZSTDds_decodeBlockHeader;

View File

@ -27,7 +27,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at : You can contact the author at :
- zstd source repository : https://github.com/Cyan4973/zstd - zstd homepage : https://www.zstd.net
*/ */
#ifndef ZSTD_CCOMMON_H_MODULE #ifndef ZSTD_CCOMMON_H_MODULE
#define ZSTD_CCOMMON_H_MODULE #define ZSTD_CCOMMON_H_MODULE
@ -78,11 +78,8 @@
#define MB *(1 <<20) #define MB *(1 <<20)
#define GB *(1U<<30) #define GB *(1U<<30)
#define BLOCKSIZE (128 KB) /* define, for static allocation */ #define ZSTD_BLOCKHEADERSIZE 3 /* because C standard does not allow a static const value to be defined using another static const value .... :( */
static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
static const size_t ZSTD_blockHeaderSize = 3;
static const size_t ZSTD_frameHeaderSize_min = 5;
#define ZSTD_frameHeaderSize_max 5 /* define, for static allocation */
#define BIT7 128 #define BIT7 128
#define BIT6 64 #define BIT6 64

View File

@ -93,8 +93,8 @@ ZSTDLIB_API unsigned ZSTD_maxCLevel (void);
/*! ZSTD_getParams() : /*! ZSTD_getParams() :
* @return ZSTD_parameters structure for a selected compression level and srcSize. * @return ZSTD_parameters structure for a selected compression level and srcSize.
* `srcSizeHint` value is optional, select 0 if not known */ * `srcSize` value is optional, select 0 if not known */
ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint); ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSize);
/*! ZSTD_validateParams() : /*! ZSTD_validateParams() :
* correct params value to remain within authorized range */ * correct params value to remain within authorized range */
@ -112,7 +112,7 @@ ZSTDLIB_API size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
* Same as ZSTD_compress_usingDict, but using a reference context `preparedCCtx`, where dictionary has been loaded. * Same as ZSTD_compress_usingDict, but using a reference context `preparedCCtx`, where dictionary has been loaded.
* It avoids reloading the dictionary each time. * It avoids reloading the dictionary each time.
* `preparedCCtx` must have been properly initialized using ZSTD_compressBegin_usingDict() or ZSTD_compressBegin_advanced(). * `preparedCCtx` must have been properly initialized using ZSTD_compressBegin_usingDict() or ZSTD_compressBegin_advanced().
* Requires 2 contexts : 1 for reference, which will not be modified, and 1 to run the compression operation */ * Requires 2 contexts : 1 for reference (preparedCCtx) which will not be modified, and 1 to run the compression operation (cctx) */
ZSTDLIB_API size_t ZSTD_compress_usingPreparedCCtx( ZSTDLIB_API size_t ZSTD_compress_usingPreparedCCtx(
ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
void* dst, size_t dstCapacity, void* dst, size_t dstCapacity,
@ -124,19 +124,19 @@ ZSTDLIB_API size_t ZSTD_compress_usingPreparedCCtx(
* Same as ZSTD_decompress_usingDict, but using a reference context `preparedDCtx`, where dictionary has been loaded. * Same as ZSTD_decompress_usingDict, but using a reference context `preparedDCtx`, where dictionary has been loaded.
* It avoids reloading the dictionary each time. * It avoids reloading the dictionary each time.
* `preparedDCtx` must have been properly initialized using ZSTD_decompressBegin_usingDict(). * `preparedDCtx` must have been properly initialized using ZSTD_decompressBegin_usingDict().
* Requires 2 contexts : 1 for reference, which will not be modified, and 1 to run the decompression operation */ * Requires 2 contexts : 1 for reference (preparedDCtx), which will not be modified, and 1 to run the decompression operation (dctx) */
ZSTDLIB_API size_t ZSTD_decompress_usingPreparedDCtx( ZSTDLIB_API size_t ZSTD_decompress_usingPreparedDCtx(
ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx, ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx,
void* dst, size_t dstCapacity, void* dst, size_t dstCapacity,
const void* src, size_t srcSize); const void* src, size_t srcSize);
/* ************************************** /* **************************************
* Streaming functions (direct mode) * Streaming functions (direct mode)
****************************************/ ****************************************/
ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);
ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict,size_t dictSize, int compressionLevel); ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel);
ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict,size_t dictSize, ZSTD_parameters params); ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params);
ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx); ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx);
ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
@ -165,13 +165,17 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapaci
You can then reuse ZSTD_CCtx to compress some new frame. You can then reuse ZSTD_CCtx to compress some new frame.
*/ */
typedef struct { U64 frameContentSize; U32 windowLog; U32 mml; } ZSTD_frameParams;
#define ZSTD_FRAMEHEADERSIZE_MAX 13 /* for static allocation */
static const size_t ZSTD_frameHeaderSize_min = 5;
static const size_t ZSTD_frameHeaderSize_max = ZSTD_FRAMEHEADERSIZE_MAX;
ZSTDLIB_API size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize); /**< doesn't consume input */
ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); 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_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx);
ZSTDLIB_API size_t ZSTD_getFrameParams(ZSTD_parameters* params, const void* src, size_t srcSize);
ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); 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); ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
@ -182,15 +186,19 @@ ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t ds
Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it. Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it.
A ZSTD_DCtx object can be re-used multiple times. A ZSTD_DCtx object can be re-used multiple times.
First typical operation is to retrieve frame parameters, using ZSTD_getFrameParams(). First optional operation is to retrieve frame parameters, using ZSTD_getFrameParams().
This operation is independent, and just needs enough input data to properly decode the frame header. It can provide the minimum size of rolling buffer required to properly decompress data,
Objective is to retrieve *params.windowlog, to know minimum amount of memory required during decoding. and optionally the final size of uncompressed content.
Result : 0 when successful, it means the ZSTD_parameters structure has been filled. (Note : content size is an optional info that may not be present. 0 means : content size unknown)
>0 : means there is not enough data into src. Provides the expected size to successfully decode header. Frame parameters are extracted from the beginning of compressed frame.
The amount of data to read is variable, from ZSTD_frameHeaderSize_min to ZSTD_frameHeaderSize_max (so if `srcSize` >= ZSTD_frameHeaderSize_max, it will always work)
If `srcSize` is too small for operation to succeed, function will return the minimum size it requires to produce a result.
Result : 0 when successful, it means the ZSTD_frameParams structure has been filled.
>0 : means there is not enough data into `src`. Provides the expected size to successfully decode header.
errorCode, which can be tested using ZSTD_isError() errorCode, which can be tested using ZSTD_isError()
Start decompression, with ZSTD_decompressBegin() or ZSTD_decompressBegin_usingDict() Start decompression, with ZSTD_decompressBegin() or ZSTD_decompressBegin_usingDict().
Alternatively, you can copy a prepared context, using ZSTD_copyDCtx() Alternatively, you can copy a prepared context, using ZSTD_copyDCtx().
Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively.
ZSTD_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTD_decompressContinue(). ZSTD_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTD_decompressContinue().
@ -198,7 +206,7 @@ ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t ds
ZSTD_decompressContinue() needs previous data blocks during decompression, up to (1 << windowlog). ZSTD_decompressContinue() needs previous data blocks during decompression, up to (1 << windowlog).
They should preferably be located contiguously, prior to current block. Alternatively, a round buffer is also possible. They should preferably be located contiguously, prior to current block. Alternatively, a round buffer is also possible.
@result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst'. @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 header. It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some header.
A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero. A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero.
@ -210,10 +218,10 @@ ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t ds
* Block functions * Block functions
****************************************/ ****************************************/
/*! Block functions produce and decode raw zstd blocks, without frame metadata. /*! Block functions produce and decode raw zstd blocks, without frame metadata.
User will have to take in charge required information to regenerate data, such as block sizes. User will have to take in charge required information to regenerate data, such as compressed and content sizes.
A few rules to respect : A few rules to respect :
- Uncompressed block size must be <= 128 KB - Uncompressed block size must be <= ZSTD_BLOCKSIZE_MAX (128 KB)
- Compressing or decompressing requires a context structure - Compressing or decompressing requires a context structure
+ Use ZSTD_createCCtx() and ZSTD_createDCtx() + Use ZSTD_createCCtx() and ZSTD_createDCtx()
- It is necessary to init context before starting - It is necessary to init context before starting
@ -227,6 +235,7 @@ ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t ds
+ ZSTD_decompressBlock() doesn't accept uncompressed data as input !! + ZSTD_decompressBlock() doesn't accept uncompressed data as input !!
*/ */
#define ZSTD_BLOCKSIZE_MAX (128 * 1024) /* define, for static allocation */
size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); 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_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);

View File

@ -112,11 +112,11 @@ zstd-frugal: $(ZSTD_FILES) $(ZSTDDIR)/zbuff.c zstdcli.c fileio.c
zstd-small: clean zstd-small: clean
CFLAGS="-Os -s" $(MAKE) zstd-frugal CFLAGS="-Os -s" $(MAKE) zstd-frugal
fullbench : $(ZSTD_FILES) \ fullbench : $(ZSTD_FILES) $(ZSTDDIR)/zbuff.c \
datagen.c fullbench.c datagen.c fullbench.c
$(CC) $(FLAGS) $^ -o $@$(EXT) $(CC) $(FLAGS) $^ -o $@$(EXT)
fullbench32: $(ZSTD_FILES) \ fullbench32: $(ZSTD_FILES) $(ZSTDDIR)/zbuff.c \
datagen.c fullbench.c datagen.c fullbench.c
$(CC) -m32 $(FLAGS) $^ -o $@$(EXT) $(CC) -m32 $(FLAGS) $^ -o $@$(EXT)

View File

@ -40,11 +40,6 @@
# define _LARGEFILE64_SOURCE # define _LARGEFILE64_SOURCE
#endif #endif
/* S_ISREG & gettimeofday() are not supported by MSVC */
#if defined(_MSC_VER) || defined(_WIN32)
# define BMK_LEGACY_TIMER 1
#endif
/* ************************************* /* *************************************
* Includes * Includes
@ -54,12 +49,17 @@
#include <stdio.h> /* fprintf, fopen, ftello64 */ #include <stdio.h> /* fprintf, fopen, ftello64 */
#include <sys/types.h> /* stat64 */ #include <sys/types.h> /* stat64 */
#include <sys/stat.h> /* stat64 */ #include <sys/stat.h> /* stat64 */
#include <time.h> /* clock_t, clock, CLOCKS_PER_SEC */
/* Use ftime() if gettimeofday() is not available */ /* sleep : posix - windows - others */
#if defined(BMK_LEGACY_TIMER) #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
# include <sys/timeb.h> /* timeb, ftime */ # include <unistd.h>
# define BMK_sleep(s) sleep(s)
#elif defined(_WIN32)
# include <windows.h>
# define BMK_sleep(s) Sleep(1000*s)
#else #else
# include <sys/time.h> /* gettimeofday */ # define BMK_sleep(s) /* disabled */
#endif #endif
#include "mem.h" #include "mem.h"
@ -88,7 +88,10 @@
# define ZSTD_VERSION "" # define ZSTD_VERSION ""
#endif #endif
#define NBLOOPS 3 #define NBLOOPS 3
#define TIMELOOP_S 1
#define ACTIVEPERIOD_S 70
#define COOLPERIOD_S 10
#define KB *(1 <<10) #define KB *(1 <<10)
#define MB *(1 <<20) #define MB *(1 <<20)
@ -127,15 +130,15 @@ static U32 g_displayLevel = 2; /* 0 : no display; 1: errors; 2 : + result
/* ************************************* /* *************************************
* Benchmark Parameters * Benchmark Parameters
***************************************/ ***************************************/
static int nbIterations = NBLOOPS; static U32 g_nbIterations = NBLOOPS;
static size_t g_blockSize = 0; static size_t g_blockSize = 0;
void BMK_setNotificationLevel(unsigned level) { g_displayLevel=level; } void BMK_setNotificationLevel(unsigned level) { g_displayLevel=level; }
void BMK_SetNbIterations(int nbLoops) void BMK_SetNbIterations(unsigned nbLoops)
{ {
nbIterations = nbLoops; g_nbIterations = nbLoops;
DISPLAYLEVEL(2, "- %i iterations -\n", nbIterations); DISPLAYLEVEL(2, "- %i iterations -\n", g_nbIterations);
} }
void BMK_SetBlockSize(size_t blockSize) void BMK_SetBlockSize(size_t blockSize)
@ -148,44 +151,11 @@ void BMK_SetBlockSize(size_t blockSize)
/* ******************************************************** /* ********************************************************
* Private functions * Private functions
**********************************************************/ **********************************************************/
static clock_t BMK_clockSpan( clock_t clockStart )
#if defined(BMK_LEGACY_TIMER)
static int BMK_GetMilliStart(void)
{ {
/* Based on Legacy ftime() return clock() - clockStart; /* works even if overflow, span limited to <= ~30mn */
* Rolls over every ~ 12.1 days (0x100000/24/60/60)
* Use GetMilliSpan to correct for rollover */
struct timeb tb;
int nCount;
ftime( &tb );
nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000);
return nCount;
} }
#else
static int BMK_GetMilliStart(void)
{
/* Based on newer gettimeofday()
* Use GetMilliSpan to correct for rollover */
struct timeval tv;
int nCount;
gettimeofday(&tv, NULL);
nCount = (int) (tv.tv_usec/1000 + (tv.tv_sec & 0xfffff) * 1000);
return nCount;
}
#endif
static int BMK_GetMilliSpan( int nTimeStart )
{
int nSpan = BMK_GetMilliStart() - nTimeStart;
if ( nSpan < 0 )
nSpan += 0x100000 * 1000;
return nSpan;
}
static U64 BMK_getFileSize(const char* infilename) static U64 BMK_getFileSize(const char* infilename)
{ {
@ -259,14 +229,14 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
/* Init blockTable data */ /* Init blockTable data */
{ {
U32 fileNb;
const char* srcPtr = (const char*)srcBuffer; const char* srcPtr = (const char*)srcBuffer;
char* cPtr = (char*)compressedBuffer; char* cPtr = (char*)compressedBuffer;
char* resPtr = (char*)resultBuffer; char* resPtr = (char*)resultBuffer;
U32 fileNb;
for (fileNb=0; fileNb<nbFiles; fileNb++) { for (fileNb=0; fileNb<nbFiles; fileNb++) {
size_t remaining = fileSizes[fileNb]; size_t remaining = fileSizes[fileNb];
U32 nbBlocksforThisFile = (U32)((remaining + (blockSize-1)) / blockSize); U32 const nbBlocksforThisFile = (U32)((remaining + (blockSize-1)) / blockSize);
U32 blockEnd = nbBlocks + nbBlocksforThisFile; U32 const blockEnd = nbBlocks + nbBlocksforThisFile;
for ( ; nbBlocks<blockEnd; nbBlocks++) { for ( ; nbBlocks<blockEnd; nbBlocks++) {
size_t thisBlockSize = MIN(remaining, blockSize); size_t thisBlockSize = MIN(remaining, blockSize);
blockTable[nbBlocks].srcPtr = srcPtr; blockTable[nbBlocks].srcPtr = srcPtr;
@ -283,32 +253,40 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
/* warmimg up memory */ /* warmimg up memory */
// int timeloop = additionalParam ? additionalParam : 2500; // int timeloop = additionalParam ? additionalParam : 2500;
int timeloop = 2500;
kSlotNew = additionalParam; kSlotNew = additionalParam;
RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.50, 1); RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.50, 1);
/* Bench */ /* Bench */
{ {
int loopNb; U32 loopNb;
double fastestC = 100000000., fastestD = 100000000.; double fastestC = 100000000., fastestD = 100000000.;
double ratio = 0.; double ratio = 0.;
U64 crcCheck = 0; U64 crcCheck = 0;
clock_t coolTime = clock();
DISPLAYLEVEL(2, "\r%79s\r", ""); DISPLAYLEVEL(2, "\r%79s\r", "");
for (loopNb = 1; loopNb <= nbIterations; loopNb++) { for (loopNb = 1; loopNb <= (g_nbIterations + !g_nbIterations); loopNb++) {
int nbLoops; int nbLoops;
int milliTime;
U32 blockNb; U32 blockNb;
clock_t clockStart, clockSpan;
clock_t const clockLoop = g_nbIterations ? TIMELOOP_S * CLOCKS_PER_SEC : 10;
/* overheat protection */
if (BMK_clockSpan(coolTime) > ACTIVEPERIOD_S * CLOCKS_PER_SEC) {
DISPLAY("\rcooling down ... \r");
BMK_sleep(COOLPERIOD_S);
coolTime = clock();
}
/* Compression */ /* Compression */
DISPLAYLEVEL(2, "%2i-%-17.17s :%10u ->\r", loopNb, displayName, (U32)srcSize); DISPLAYLEVEL(2, "%2i-%-17.17s :%10u ->\r", loopNb, displayName, (U32)srcSize);
memset(compressedBuffer, 0xE5, maxCompressedSize); memset(compressedBuffer, 0xE5, maxCompressedSize); /* warm up and erase result buffer */
nbLoops = 0; nbLoops = 0;
milliTime = BMK_GetMilliStart(); clockStart = clock();
while (BMK_GetMilliStart() == milliTime); while (clock() == clockStart);
milliTime = BMK_GetMilliStart(); clockStart = clock();
while (BMK_GetMilliSpan(milliTime) < timeloop) { while (BMK_clockSpan(clockStart) < clockLoop) {
ZSTD_compressBegin_advanced(refCtx, dictBuffer, dictBufferSize, ZSTD_getParams(cLevel, MAX(dictBufferSize, largestBlockSize))); ZSTD_compressBegin_advanced(refCtx, dictBuffer, dictBufferSize, ZSTD_getParams(cLevel, MAX(dictBufferSize, largestBlockSize)));
for (blockNb=0; blockNb<nbBlocks; blockNb++) { for (blockNb=0; blockNb<nbBlocks; blockNb++) {
size_t rSize = ZSTD_compress_usingPreparedCCtx(ctx, refCtx, size_t rSize = ZSTD_compress_usingPreparedCCtx(ctx, refCtx,
@ -319,25 +297,27 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
} }
nbLoops++; nbLoops++;
} }
milliTime = BMK_GetMilliSpan(milliTime); clockSpan = BMK_clockSpan(clockStart);
cSize = 0; cSize = 0;
for (blockNb=0; blockNb<nbBlocks; blockNb++) for (blockNb=0; blockNb<nbBlocks; blockNb++)
cSize += blockTable[blockNb].cSize; cSize += blockTable[blockNb].cSize;
if ((double)milliTime < fastestC*nbLoops) fastestC = (double)milliTime / nbLoops; if ((double)clockSpan < fastestC*nbLoops) fastestC = (double)clockSpan / nbLoops;
ratio = (double)srcSize / (double)cSize; ratio = (double)srcSize / (double)cSize;
DISPLAYLEVEL(2, "%2i-%-17.17s :%10i ->%10i (%5.3f),%6.1f MB/s\r", loopNb, displayName, (int)srcSize, (int)cSize, ratio, (double)srcSize / fastestC / 1000.); DISPLAYLEVEL(2, "%2i-%-17.17s :%10u ->%10u (%5.3f),%6.1f MB/s\r",
loopNb, displayName, (U32)srcSize, (U32)cSize, ratio,
(double)srcSize / 1000000. / (fastestC / CLOCKS_PER_SEC) );
#if 1 #if 1
/* Decompression */ /* Decompression */
memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */ memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */
nbLoops = 0; nbLoops = 0;
milliTime = BMK_GetMilliStart(); clockStart = clock();
while (BMK_GetMilliStart() == milliTime); while (clock() == clockStart);
milliTime = BMK_GetMilliStart(); clockStart = clock();
for ( ; BMK_GetMilliSpan(milliTime) < timeloop; nbLoops++) { for ( ; BMK_clockSpan(clockStart) < clockLoop; nbLoops++) {
ZSTD_decompressBegin_usingDict(refDCtx, dictBuffer, dictBufferSize); ZSTD_decompressBegin_usingDict(refDCtx, dictBuffer, dictBufferSize);
for (blockNb=0; blockNb<nbBlocks; blockNb++) { for (blockNb=0; blockNb<nbBlocks; blockNb++) {
size_t regenSize = ZSTD_decompress_usingPreparedDCtx(dctx, refDCtx, size_t regenSize = ZSTD_decompress_usingPreparedDCtx(dctx, refDCtx,
@ -351,9 +331,12 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
blockTable[blockNb].resSize = regenSize; blockTable[blockNb].resSize = regenSize;
} } } }
milliTime = BMK_GetMilliSpan(milliTime); clockSpan = BMK_clockSpan(clockStart);
if ((double)milliTime < fastestD*nbLoops) fastestD = (double)milliTime / nbLoops; if ((double)clockSpan < fastestD*nbLoops) fastestD = (double)clockSpan / nbLoops;
DISPLAYLEVEL(2, "%2i-%-17.17s :%10i ->%10i (%5.3f),%6.1f MB/s ,%6.1f MB/s\r", loopNb, displayName, (int)srcSize, (int)cSize, ratio, (double)srcSize / fastestC / 1000., (double)srcSize / fastestD / 1000.); DISPLAYLEVEL(2, "%2i-%-17.17s :%10u ->%10u (%5.3f),%6.1f MB/s ,%6.1f MB/s\r",
loopNb, displayName, (U32)srcSize, (U32)cSize, ratio,
(double)srcSize / 1000000. / (fastestC / CLOCKS_PER_SEC),
(double)srcSize / 1000000. / (fastestD / CLOCKS_PER_SEC) );
/* CRC Checking */ /* CRC Checking */
_findError: _findError:
@ -439,7 +422,7 @@ static void BMK_benchCLevel(void* srcBuffer, size_t benchedSize,
memset(&total, 0, sizeof(total)); memset(&total, 0, sizeof(total));
if (g_displayLevel == 1 && !additionalParam) if (g_displayLevel == 1 && !additionalParam)
DISPLAY("bench %s: input %u bytes, %i iterations, %u KB blocks\n", ZSTD_VERSION, (U32)benchedSize, nbIterations, (U32)(g_blockSize>>10)); DISPLAY("bench %s: input %u bytes, %i iterations, %u KB blocks\n", ZSTD_VERSION, (U32)benchedSize, g_nbIterations, (U32)(g_blockSize>>10));
if (cLevelLast < cLevel) cLevelLast = cLevel; if (cLevelLast < cLevel) cLevelLast = cLevel;
@ -480,12 +463,11 @@ static U64 BMK_getTotalFileSize(const char** fileNamesTable, unsigned nbFiles)
static void BMK_loadFiles(void* buffer, size_t bufferSize, static void BMK_loadFiles(void* buffer, size_t bufferSize,
size_t* fileSizes, size_t* fileSizes,
const char** fileNamesTable, unsigned nbFiles) const char** fileNamesTable, unsigned const nbFiles)
{ {
BYTE* buff = (BYTE*)buffer;
size_t pos = 0; size_t pos = 0;
unsigned n;
unsigned n;
for (n=0; n<nbFiles; n++) { for (n=0; n<nbFiles; n++) {
size_t readSize; size_t readSize;
U64 fileSize = BMK_getFileSize(fileNamesTable[n]); U64 fileSize = BMK_getFileSize(fileNamesTable[n]);
@ -493,7 +475,7 @@ static void BMK_loadFiles(void* buffer, size_t bufferSize,
if (f==NULL) EXM_THROW(10, "impossible to open file %s", fileNamesTable[n]); if (f==NULL) EXM_THROW(10, "impossible to open file %s", fileNamesTable[n]);
DISPLAYLEVEL(2, "Loading %s... \r", fileNamesTable[n]); DISPLAYLEVEL(2, "Loading %s... \r", fileNamesTable[n]);
if (fileSize > bufferSize-pos) fileSize = bufferSize-pos; if (fileSize > bufferSize-pos) fileSize = bufferSize-pos;
readSize = fread(buff+pos, 1, (size_t)fileSize, f); readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f);
if (readSize != (size_t)fileSize) EXM_THROW(11, "could not read %s", fileNamesTable[n]); if (readSize != (size_t)fileSize) EXM_THROW(11, "could not read %s", fileNamesTable[n]);
pos += readSize; pos += readSize;
fileSizes[n] = (size_t)fileSize; fileSizes[n] = (size_t)fileSize;
@ -577,7 +559,7 @@ static void BMK_syntheticTest(int cLevel, int cLevelLast, int additionalParam, d
int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles, int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles,
const char* dictFileName, int cLevel, int cLevelLast, int additionalParam) const char* dictFileName, int cLevel, int cLevelLast, int additionalParam)
{ {
double compressibility = (double)g_compressibilityDefault / 100; double const compressibility = (double)g_compressibilityDefault / 100;
if (nbFiles == 0) if (nbFiles == 0)
BMK_syntheticTest(cLevel, cLevelLast, additionalParam, compressibility); BMK_syntheticTest(cLevel, cLevelLast, additionalParam, compressibility);

View File

@ -30,7 +30,7 @@ int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles,
const char* dictFileName, int cLevel, int cLevelLast, int additionalParam); const char* dictFileName, int cLevel, int cLevelLast, int additionalParam);
/* Set Parameters */ /* Set Parameters */
void BMK_SetNbIterations(int nbLoops); void BMK_SetNbIterations(unsigned nbLoops);
void BMK_SetBlockSize(size_t blockSize); void BMK_SetBlockSize(size_t blockSize);
void BMK_setNotificationLevel(unsigned level); void BMK_setNotificationLevel(unsigned level);

View File

@ -64,7 +64,7 @@
#include <sys/stat.h> /* stat64 */ #include <sys/stat.h> /* stat64 */
#include "mem.h" #include "mem.h"
#include "fileio.h" #include "fileio.h"
#include "zstd_static.h" /* ZSTD_magicNumber */ #include "zstd_static.h" /* ZSTD_magicNumber, ZSTD_frameHeaderSize_max */
#include "zbuff_static.h" #include "zbuff_static.h"
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1) #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1)
@ -126,6 +126,7 @@
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__) #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
static U32 g_displayLevel = 2; /* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */ static U32 g_displayLevel = 2; /* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */
void FIO_setNotificationLevel(unsigned level) { g_displayLevel=level; }
#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
if ((FIO_GetMilliSpan(g_time) > refreshRate) || (g_displayLevel>=4)) \ if ((FIO_GetMilliSpan(g_time) > refreshRate) || (g_displayLevel>=4)) \
@ -142,7 +143,8 @@ static clock_t g_time = 0;
***************************************/ ***************************************/
static U32 g_overwrite = 0; static U32 g_overwrite = 0;
void FIO_overwriteMode(void) { g_overwrite=1; } void FIO_overwriteMode(void) { g_overwrite=1; }
void FIO_setNotificationLevel(unsigned level) { g_displayLevel=level; } static U32 g_maxWLog = 23;
void FIO_setMaxWLog(unsigned maxWLog) { g_maxWLog = maxWLog; }
/*-************************************* /*-*************************************
@ -239,10 +241,10 @@ static FILE* FIO_openDstFile(const char* dstFileName)
} }
/*!FIO_loadFile /*! FIO_loadFile() :
* creates a buffer, pointed by *bufferPtr, * creates a buffer, pointed by `*bufferPtr`,
* loads "filename" content into it * loads `filename` content into it,
* up to MAX_DICT_SIZE bytes * up to MAX_DICT_SIZE bytes
*/ */
static size_t FIO_loadFile(void** bufferPtr, const char* fileName) static size_t FIO_loadFile(void** bufferPtr, const char* fileName)
{ {
@ -274,7 +276,7 @@ static size_t FIO_loadFile(void** bufferPtr, const char* fileName)
} }
/* ********************************************************************** /*-**********************************************************************
* Compression * Compression
************************************************************************/ ************************************************************************/
typedef struct { typedef struct {
@ -321,7 +323,7 @@ static void FIO_freeCResources(cRess_t ress)
/*! FIO_compressFilename_internal() : /*! FIO_compressFilename_internal() :
* same as FIO_compressFilename_extRess(), with ress.desFile already opened * same as FIO_compressFilename_extRess(), with `ress.desFile` already opened.
* @return : 0 : compression completed correctly, * @return : 0 : compression completed correctly,
* 1 : missing or pb opening srcFileName * 1 : missing or pb opening srcFileName
*/ */
@ -335,10 +337,14 @@ static int FIO_compressFilename_internal(cRess_t ress,
U64 compressedfilesize = 0; U64 compressedfilesize = 0;
size_t dictSize = ress.dictBufferSize; size_t dictSize = ress.dictBufferSize;
size_t sizeCheck, errorCode; size_t sizeCheck, errorCode;
ZSTD_parameters params;
/* init */ /* init */
filesize = MAX(FIO_getFileSize(srcFileName),dictSize); filesize = MAX(FIO_getFileSize(srcFileName),dictSize);
errorCode = ZBUFF_compressInit_advanced(ress.ctx, ress.dictBuffer, ress.dictBufferSize, ZSTD_getParams(cLevel, filesize)); params = ZSTD_getParams(cLevel, filesize);
params.srcSize = filesize;
if (g_maxWLog) if (params.windowLog > g_maxWLog) params.windowLog = g_maxWLog;
errorCode = ZBUFF_compressInit_advanced(ress.ctx, ress.dictBuffer, ress.dictBufferSize, params);
if (ZBUFF_isError(errorCode)) EXM_THROW(21, "Error initializing compression : %s", ZBUFF_getErrorName(errorCode)); if (ZBUFF_isError(errorCode)) EXM_THROW(21, "Error initializing compression : %s", ZBUFF_getErrorName(errorCode));
/* Main compression loop */ /* Main compression loop */
@ -389,7 +395,7 @@ static int FIO_compressFilename_internal(cRess_t ress,
/*! FIO_compressFilename_internal() : /*! FIO_compressFilename_internal() :
* same as FIO_compressFilename_extRess(), with ress.desFile already opened * same as FIO_compressFilename_extRess(), with ress.destFile already opened (typically stdout)
* @return : 0 : compression completed correctly, * @return : 0 : compression completed correctly,
* 1 : missing or pb opening srcFileName * 1 : missing or pb opening srcFileName
*/ */
@ -427,6 +433,7 @@ static int FIO_compressFilename_extRess(cRess_t ress,
if (ress.dstFile==0) { fclose(ress.srcFile); return 1; } if (ress.dstFile==0) { fclose(ress.srcFile); return 1; }
result = FIO_compressFilename_internal(ress, dstFileName, srcFileName, cLevel); result = FIO_compressFilename_internal(ress, dstFileName, srcFileName, cLevel);
if (result!=0) remove(dstFileName); /* remove operation artefact */
fclose(ress.srcFile); /* no pb to expect : only reading */ fclose(ress.srcFile); /* no pb to expect : only reading */
if (fclose(ress.dstFile)) EXM_THROW(28, "Write error : cannot properly close %s", dstFileName); if (fclose(ress.dstFile)) EXM_THROW(28, "Write error : cannot properly close %s", dstFileName);
@ -482,7 +489,7 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile
ress.dstFile = stdout; ress.dstFile = stdout;
for (u=0; u<nbFiles; u++) for (u=0; u<nbFiles; u++)
missed_files += FIO_compressFilename_srcFile(ress, stdoutmark, missed_files += FIO_compressFilename_srcFile(ress, stdoutmark,
inFileNamesTable[u], compressionLevel); inFileNamesTable[u], compressionLevel);
if (fclose(ress.dstFile)) EXM_THROW(29, "Write error : cannot properly close %s", stdoutmark); if (fclose(ress.dstFile)) EXM_THROW(29, "Write error : cannot properly close %s", stdoutmark);
} else { } else {
for (u=0; u<nbFiles; u++) { for (u=0; u<nbFiles; u++) {
@ -547,35 +554,46 @@ static void FIO_freeDResources(dRess_t ress)
} }
/** FIO_decompressFrame() :
@return : size of decoded frame
*/
unsigned long long FIO_decompressFrame(dRess_t ress, unsigned long long FIO_decompressFrame(dRess_t ress,
FILE* foutput, FILE* finput, size_t alreadyLoaded) FILE* foutput, FILE* finput, size_t alreadyLoaded)
{ {
U64 frameSize = 0; U64 frameSize = 0;
size_t readSize=alreadyLoaded; size_t readSize;
ZBUFF_decompressInitDictionary(ress.dctx, ress.dictBuffer, ress.dictBufferSize);
/* Complete Header loading */
{ size_t const toLoad = ZSTD_frameHeaderSize_max - alreadyLoaded; /* assumption : alreadyLoaded <= ZSTD_frameHeaderSize_max */
size_t const checkSize = fread(((char*)ress.srcBuffer) + alreadyLoaded, 1, toLoad, finput);
if (checkSize != toLoad) EXM_THROW(32, "Read error");
}
readSize = ZSTD_frameHeaderSize_max;
/* Main decompression Loop */ /* Main decompression Loop */
ZBUFF_decompressInitDictionary(ress.dctx, ress.dictBuffer, ress.dictBufferSize);
while (1) { while (1) {
/* Decode */ /* Decode */
size_t sizeCheck;
size_t inSize=readSize, decodedSize=ress.dstBufferSize; size_t inSize=readSize, decodedSize=ress.dstBufferSize;
size_t toRead = ZBUFF_decompressContinue(ress.dctx, ress.dstBuffer, &decodedSize, ress.srcBuffer, &inSize); size_t toRead = ZBUFF_decompressContinue(ress.dctx, ress.dstBuffer, &decodedSize, ress.srcBuffer, &inSize);
if (ZBUFF_isError(toRead)) EXM_THROW(36, "Decoding error : %s", ZBUFF_getErrorName(toRead)); if (ZBUFF_isError(toRead)) EXM_THROW(36, "Decoding error : %s", ZBUFF_getErrorName(toRead));
readSize -= inSize; readSize -= inSize;
/* Write block */ /* Write block */
sizeCheck = fwrite(ress.dstBuffer, 1, decodedSize, foutput); { size_t const sizeCheck = fwrite(ress.dstBuffer, 1, decodedSize, foutput);
if (sizeCheck != decodedSize) EXM_THROW(37, "Write error : unable to write data block to destination file"); if (sizeCheck != decodedSize) EXM_THROW(37, "Write error : unable to write data block into destination"); }
frameSize += decodedSize; frameSize += decodedSize;
DISPLAYUPDATE(2, "\rDecoded : %u MB... ", (U32)(frameSize>>20) ); DISPLAYUPDATE(2, "\rDecoded : %u MB... ", (U32)(frameSize>>20) );
if (toRead == 0) break; if (toRead == 0) break; /* end of frame */
if (readSize) EXM_THROW(38, "Decoding error : should consume entire input"); if (readSize) EXM_THROW(38, "Decoding error : should consume entire input");
/* Fill input buffer */ /* Fill input buffer */
if (toRead > ress.srcBufferSize) EXM_THROW(34, "too large block"); if (toRead > ress.srcBufferSize) EXM_THROW(34, "too large block");
readSize = fread(ress.srcBuffer, 1, toRead, finput); readSize = fread(ress.srcBuffer, 1, toRead, finput);
if (readSize != toRead) EXM_THROW(35, "Read error"); if (readSize != toRead)
EXM_THROW(35, "Read error");
} }
return frameSize; return frameSize;
@ -633,13 +651,17 @@ static int FIO_decompressSrcFile(dRess_t ress, const char* srcFileName)
static int FIO_decompressFile_extRess(dRess_t ress, static int FIO_decompressFile_extRess(dRess_t ress,
const char* dstFileName, const char* srcFileName) const char* dstFileName, const char* srcFileName)
{ {
int result;
ress.dstFile = FIO_openDstFile(dstFileName); ress.dstFile = FIO_openDstFile(dstFileName);
if (ress.dstFile==0) return 1; if (ress.dstFile==0) return 1;
FIO_decompressSrcFile(ress, srcFileName); result = FIO_decompressSrcFile(ress, srcFileName);
if (result != 0) {
remove(dstFileName);
}
if (fclose(ress.dstFile)) EXM_THROW(38, "Write error : cannot properly close %s", dstFileName); if (fclose(ress.dstFile)) EXM_THROW(38, "Write error : cannot properly close %s", dstFileName);
return 0; return result;
} }

View File

@ -41,14 +41,15 @@ extern "C" {
#endif #endif
/* ************************************* /*-*************************************
* Parameters * Parameters
***************************************/ ***************************************/
void FIO_overwriteMode(void); void FIO_overwriteMode(void);
void FIO_setNotificationLevel(unsigned level); void FIO_setNotificationLevel(unsigned level);
void FIO_setMaxWLog(unsigned maxWLog); /**< if `maxWLog` == 0, no max enforced */
/* ************************************* /*-*************************************
* Single File functions * Single File functions
***************************************/ ***************************************/
/** FIO_compressFilename() : /** FIO_compressFilename() :
@ -60,7 +61,7 @@ int FIO_compressFilename (const char* outfilename, const char* infilename, const
int FIO_decompressFilename (const char* outfilename, const char* infilename, const char* dictFileName); int FIO_decompressFilename (const char* outfilename, const char* infilename, const char* dictFileName);
/* ************************************* /*-*************************************
* Multiple File functions * Multiple File functions
***************************************/ ***************************************/
/** FIO_compressMultipleFilenames() : /** FIO_compressMultipleFilenames() :

View File

@ -1,6 +1,6 @@
/* /*
fullbench.c - Detailed bench program for zstd fullbench.c - Detailed bench program for zstd
Copyright (C) Yann Collet 2014-2015 Copyright (C) Yann Collet 2014-2016
GPL v2 License GPL v2 License
@ -19,11 +19,10 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
You can contact the author at : You can contact the author at :
- zstd source repository : https://github.com/Cyan4973/zstd - zstd homepage : http://www.zstd.net
- ztsd public forum : https://groups.google.com/forum/#!forum/lz4c
*/ */
/************************************** /*_************************************
* Compiler Options * Compiler Options
**************************************/ **************************************/
/* Disable some Visual warning messages */ /* Disable some Visual warning messages */
@ -38,13 +37,8 @@
# define _LARGEFILE64_SOURCE # define _LARGEFILE64_SOURCE
#endif #endif
/* S_ISREG & gettimeofday() are not supported by MSVC */
#if defined(_MSC_VER) || defined(_WIN32)
# define BMK_LEGACY_TIMER 1
#endif
/*_************************************
/**************************************
* Includes * Includes
**************************************/ **************************************/
#include <stdlib.h> /* malloc */ #include <stdlib.h> /* malloc */
@ -52,21 +46,16 @@
#include <sys/types.h> /* stat64 */ #include <sys/types.h> /* stat64 */
#include <sys/stat.h> /* stat64 */ #include <sys/stat.h> /* stat64 */
#include <string.h> /* strcmp */ #include <string.h> /* strcmp */
#include <time.h> /* clock_t, clock, CLOCKS_PER_SEC */
/* Use ftime() if gettimeofday() is not available on your target */
#if defined(BMK_LEGACY_TIMER)
# include <sys/timeb.h> /* timeb, ftime */
#else
# include <sys/time.h> /* gettimeofday */
#endif
#include "mem.h" #include "mem.h"
#include "zstd_static.h" #include "zstd_static.h"
#include "fse_static.h" #include "fse_static.h"
#include "zbuff.h"
#include "datagen.h" #include "datagen.h"
/************************************** /*_************************************
* Compiler Options * Compiler Options
**************************************/ **************************************/
/* S_ISREG & gettimeofday() are not supported by MSVC */ /* S_ISREG & gettimeofday() are not supported by MSVC */
@ -75,7 +64,7 @@
#endif #endif
/************************************** /*_************************************
* Constants * Constants
**************************************/ **************************************/
#define PROGRAM_DESCRIPTION "Zstandard speed analyzer" #define PROGRAM_DESCRIPTION "Zstandard speed analyzer"
@ -90,98 +79,63 @@
#define MB *(1<<20) #define MB *(1<<20)
#define NBLOOPS 6 #define NBLOOPS 6
#define TIMELOOP 2500 #define TIMELOOP_S 2
#define KNUTH 2654435761U #define KNUTH 2654435761U
#define MAX_MEM (1984 MB) #define MAX_MEM (1984 MB)
#define COMPRESSIBILITY_DEFAULT 0.50 #define COMPRESSIBILITY_DEFAULT 0.50
static const size_t sampleSize = 10000000; static const size_t g_sampleSize = 10000000;
/************************************** /*_************************************
* Macros * Macros
**************************************/ **************************************/
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__) #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
/************************************** /*_************************************
* Benchmark Parameters * Benchmark Parameters
**************************************/ **************************************/
static int nbIterations = NBLOOPS; static U32 g_nbIterations = NBLOOPS;
static double g_compressibility = COMPRESSIBILITY_DEFAULT; static double g_compressibility = COMPRESSIBILITY_DEFAULT;
void BMK_SetNbIterations(int nbLoops) static void BMK_SetNbIterations(U32 nbLoops)
{ {
nbIterations = nbLoops; g_nbIterations = nbLoops;
DISPLAY("- %i iterations -\n", nbIterations); DISPLAY("- %i iterations -\n", g_nbIterations);
} }
/********************************************************* /*_*******************************************************
* Private functions * Private functions
*********************************************************/ *********************************************************/
static clock_t BMK_clockSpan( clock_t clockStart )
#if defined(BMK_LEGACY_TIMER)
static int BMK_GetMilliStart(void)
{ {
/* Based on Legacy ftime() return clock() - clockStart; /* works even if overflow, span limited to <= ~30mn */
* Rolls over every ~ 12.1 days (0x100000/24/60/60)
* Use GetMilliSpan to correct for rollover */
struct timeb tb;
int nCount;
ftime( &tb );
nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000);
return nCount;
}
#else
static int BMK_GetMilliStart(void)
{
/* Based on newer gettimeofday()
* Use GetMilliSpan to correct for rollover */
struct timeval tv;
int nCount;
gettimeofday(&tv, NULL);
nCount = (int) (tv.tv_usec/1000 + (tv.tv_sec & 0xfffff) * 1000);
return nCount;
}
#endif
static int BMK_GetMilliSpan( int nTimeStart )
{
int nSpan = BMK_GetMilliStart() - nTimeStart;
if ( nSpan < 0 )
nSpan += 0x100000 * 1000;
return nSpan;
} }
static size_t BMK_findMaxMem(U64 requiredMem) static size_t BMK_findMaxMem(U64 requiredMem)
{ {
size_t step = 64 MB; const size_t step = 64 MB;
BYTE* testmem=NULL; void* testmem = NULL;
requiredMem = (((requiredMem >> 26) + 1) << 26); requiredMem = (((requiredMem >> 26) + 1) << 26);
if (requiredMem > MAX_MEM) requiredMem = MAX_MEM; if (requiredMem > MAX_MEM) requiredMem = MAX_MEM;
requiredMem += 2*step; requiredMem += step;
while (!testmem) do {
{ testmem = malloc ((size_t)requiredMem);
requiredMem -= step; requiredMem -= step;
testmem = (BYTE*) malloc ((size_t)requiredMem); } while (!testmem);
}
free (testmem); free (testmem);
return (size_t) (requiredMem - step); return (size_t) requiredMem;
} }
static U64 BMK_GetFileSize(char* infilename) static U64 BMK_GetFileSize(const char* infilename)
{ {
int r; int r;
#if defined(_MSC_VER) #if defined(_MSC_VER)
@ -196,42 +150,39 @@ static U64 BMK_GetFileSize(char* infilename)
} }
/********************************************************* /*_*******************************************************
* Benchmark wrappers * Benchmark wrappers
*********************************************************/ *********************************************************/
typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t; typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t;
typedef struct typedef struct {
{
blockType_t blockType; blockType_t blockType;
U32 unusedBits; U32 unusedBits;
U32 origSize; U32 origSize;
} blockProperties_t; } blockProperties_t;
static size_t g_cSize = 0;
static ZSTD_DCtx* g_dctxPtr = NULL;
extern size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr);
extern size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLengthPtr, FSE_DTable* DTableLL, FSE_DTable* DTableML, FSE_DTable* DTableOffb, const void* src, size_t srcSize);
size_t local_ZSTD_compress(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) size_t local_ZSTD_compress(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize)
{ {
(void)buff2; (void)buff2;
return ZSTD_compress(dst, dstSize, src, srcSize, 1); return ZSTD_compress(dst, dstSize, src, srcSize, 1);
} }
static size_t g_cSize = 0;
size_t local_ZSTD_decompress(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) size_t local_ZSTD_decompress(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize)
{ {
(void)src; (void)srcSize; (void)src; (void)srcSize;
return ZSTD_decompress(dst, dstSize, buff2, g_cSize); return ZSTD_decompress(dst, dstSize, buff2, g_cSize);
} }
static ZSTD_DCtx* g_zdc = NULL;
extern size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* ctx, const void* src, size_t srcSize); extern size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* ctx, const void* src, size_t srcSize);
size_t local_ZSTD_decodeLiteralsBlock(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) size_t local_ZSTD_decodeLiteralsBlock(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize)
{ {
(void)src; (void)srcSize; (void)dst; (void)dstSize; (void)src; (void)srcSize; (void)dst; (void)dstSize;
return ZSTD_decodeLiteralsBlock((ZSTD_DCtx*)g_dctxPtr, buff2, g_cSize); return ZSTD_decodeLiteralsBlock((ZSTD_DCtx*)g_zdc, buff2, g_cSize);
} }
extern size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr);
extern size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLengthPtr, FSE_DTable* DTableLL, FSE_DTable* DTableML, FSE_DTable* DTableOffb, const void* src, size_t srcSize);
size_t local_ZSTD_decodeSeqHeaders(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) size_t local_ZSTD_decodeSeqHeaders(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize)
{ {
U32 DTableML[FSE_DTABLE_SIZE_U32(10)], DTableLL[FSE_DTABLE_SIZE_U32(10)], DTableOffb[FSE_DTABLE_SIZE_U32(9)]; /* MLFSELog, LLFSELog and OffFSELog are not public values */ U32 DTableML[FSE_DTABLE_SIZE_U32(10)], DTableLL[FSE_DTABLE_SIZE_U32(10)], DTableOffb[FSE_DTABLE_SIZE_U32(9)]; /* MLFSELog, LLFSELog and OffFSELog are not public values */
@ -243,20 +194,76 @@ size_t local_ZSTD_decodeSeqHeaders(void* dst, size_t dstSize, void* buff2, const
} }
static ZBUFF_CCtx* g_zbcc = NULL;
size_t local_ZBUFF_compress(void* dst, size_t dstCapacity, void* buff2, const void* src, size_t srcSize)
{
size_t compressedSize;
size_t srcRead = srcSize, dstWritten = dstCapacity;
(void)buff2;
ZBUFF_compressInit(g_zbcc, 1);
ZBUFF_compressContinue(g_zbcc, dst, &dstWritten, src, &srcRead);
compressedSize = dstWritten;
dstWritten = dstCapacity-compressedSize;
ZBUFF_compressEnd(g_zbcc, ((char*)dst)+compressedSize, &dstWritten);
compressedSize += dstWritten;
return compressedSize;
}
/********************************************************* static ZBUFF_DCtx* g_zbdc = NULL;
static size_t local_ZBUFF_decompress(void* dst, size_t dstCapacity, void* buff2, const void* src, size_t srcSize)
{
size_t srcRead = g_cSize, dstWritten = dstCapacity;
(void)src; (void)srcSize;
ZBUFF_decompressInit(g_zbdc);
ZBUFF_decompressContinue(g_zbdc, dst, &dstWritten, buff2, &srcRead);
return dstWritten;
}
static ZSTD_CCtx* g_zcc = NULL;
size_t local_ZSTD_compressContinue(void* dst, size_t dstCapacity, void* buff2, const void* src, size_t srcSize)
{
size_t compressedSize;
(void)buff2;
ZSTD_compressBegin(g_zcc, 1);
compressedSize = ZSTD_compressContinue(g_zcc, dst, dstCapacity, src, srcSize);
compressedSize += ZSTD_compressEnd(g_zcc, ((char*)dst)+compressedSize, dstCapacity-compressedSize);
return compressedSize;
}
size_t local_ZSTD_decompressContinue(void* dst, size_t dstCapacity, void* buff2, const void* src, size_t srcSize)
{
size_t regeneratedSize = 0;
const BYTE* ip = (const BYTE*)buff2;
const BYTE* const iend = ip + g_cSize;
BYTE* op = (BYTE*)dst;
size_t remainingCapacity = dstCapacity;
(void)src; (void)srcSize;
ZSTD_decompressBegin(g_zdc);
while (ip < iend) {
size_t const iSize = ZSTD_nextSrcSizeToDecompress(g_zdc);
size_t const decodedSize = ZSTD_decompressContinue(g_zdc, op, remainingCapacity, ip, iSize);
ip += iSize;
regeneratedSize += decodedSize;
op += decodedSize;
remainingCapacity -= decodedSize;
}
return regeneratedSize;
}
/*_*******************************************************
* Bench functions * Bench functions
*********************************************************/ *********************************************************/
size_t benchMem(void* src, size_t srcSize, U32 benchNb) static size_t benchMem(const void* src, size_t srcSize, U32 benchNb)
{ {
BYTE* dstBuff; BYTE* dstBuff;
size_t dstBuffSize; size_t dstBuffSize;
BYTE* buff2; BYTE* buff2;
int loopNb;
const char* benchName; const char* benchName;
size_t (*benchFunction)(void* dst, size_t dstSize, void* verifBuff, const void* src, size_t srcSize); size_t (*benchFunction)(void* dst, size_t dstSize, void* verifBuff, const void* src, size_t srcSize);
double bestTime = 100000000.; double bestTime = 100000000.;
size_t errorCode = 0;
/* Selection */ /* Selection */
switch(benchNb) switch(benchNb)
@ -264,15 +271,27 @@ size_t benchMem(void* src, size_t srcSize, U32 benchNb)
case 1: case 1:
benchFunction = local_ZSTD_compress; benchName = "ZSTD_compress"; benchFunction = local_ZSTD_compress; benchName = "ZSTD_compress";
break; break;
case 11: case 2:
benchFunction = local_ZSTD_decompress; benchName = "ZSTD_decompress"; benchFunction = local_ZSTD_decompress; benchName = "ZSTD_decompress";
break; break;
case 11:
benchFunction = local_ZSTD_compressContinue; benchName = "ZSTD_compressContinue";
break;
case 12:
benchFunction = local_ZSTD_decompressContinue; benchName = "ZSTD_decompressContinue";
break;
case 31: case 31:
benchFunction = local_ZSTD_decodeLiteralsBlock; benchName = "ZSTD_decodeLiteralsBlock"; benchFunction = local_ZSTD_decodeLiteralsBlock; benchName = "ZSTD_decodeLiteralsBlock";
break; break;
case 32: case 32:
benchFunction = local_ZSTD_decodeSeqHeaders; benchName = "ZSTD_decodeSeqHeaders"; benchFunction = local_ZSTD_decodeSeqHeaders; benchName = "ZSTD_decodeSeqHeaders";
break; break;
case 41:
benchFunction = local_ZBUFF_compress; benchName = "ZBUFF_compressContinue";
break;
case 42:
benchFunction = local_ZBUFF_decompress; benchName = "ZBUFF_decompressContinue";
break;
default : default :
return 0; return 0;
} }
@ -281,9 +300,7 @@ size_t benchMem(void* src, size_t srcSize, U32 benchNb)
dstBuffSize = ZSTD_compressBound(srcSize); dstBuffSize = ZSTD_compressBound(srcSize);
dstBuff = (BYTE*)malloc(dstBuffSize); dstBuff = (BYTE*)malloc(dstBuffSize);
buff2 = (BYTE*)malloc(dstBuffSize); buff2 = (BYTE*)malloc(dstBuffSize);
g_dctxPtr = ZSTD_createDCtx(); if ((!dstBuff) || (!buff2)) {
if ((!dstBuff) || (!buff2))
{
DISPLAY("\nError: not enough memory!\n"); DISPLAY("\nError: not enough memory!\n");
free(dstBuff); free(buff2); free(dstBuff); free(buff2);
return 12; return 12;
@ -292,45 +309,66 @@ size_t benchMem(void* src, size_t srcSize, U32 benchNb)
/* Preparation */ /* Preparation */
switch(benchNb) switch(benchNb)
{ {
case 11: case 2:
g_cSize = ZSTD_compress(buff2, dstBuffSize, src, srcSize, 1);
break;
case 11 :
if (g_zcc==NULL) g_zcc = ZSTD_createCCtx();
break;
case 12 :
if (g_zdc==NULL) g_zdc = ZSTD_createDCtx();
g_cSize = ZSTD_compress(buff2, dstBuffSize, src, srcSize, 1); g_cSize = ZSTD_compress(buff2, dstBuffSize, src, srcSize, 1);
break; break;
case 31: /* ZSTD_decodeLiteralsBlock */ case 31: /* ZSTD_decodeLiteralsBlock */
{ if (g_zdc==NULL) g_zdc = ZSTD_createDCtx();
blockProperties_t bp; { blockProperties_t bp;
ZSTD_frameParams zfp;
size_t frameHeaderSize, skippedSize;
g_cSize = ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1); g_cSize = ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1);
ZSTD_getcBlockSize(dstBuff+4, dstBuffSize, &bp); /* Get 1st block type */ frameHeaderSize = ZSTD_getFrameParams(&zfp, dstBuff, ZSTD_frameHeaderSize_min);
if (bp.blockType != bt_compressed) if (frameHeaderSize==0) frameHeaderSize = ZSTD_frameHeaderSize_min;
{ ZSTD_getcBlockSize(dstBuff+frameHeaderSize, dstBuffSize, &bp); /* Get 1st block type */
if (bp.blockType != bt_compressed) {
DISPLAY("ZSTD_decodeLiteralsBlock : impossible to test on this sample (not compressible)\n"); DISPLAY("ZSTD_decodeLiteralsBlock : impossible to test on this sample (not compressible)\n");
goto _cleanOut; goto _cleanOut;
} }
memcpy(buff2, dstBuff+8, g_cSize-8); skippedSize = frameHeaderSize + 3 /* ZSTD_blockHeaderSize */;
memcpy(buff2, dstBuff+skippedSize, g_cSize-skippedSize);
srcSize = srcSize > 128 KB ? 128 KB : srcSize; /* speed relative to block */ srcSize = srcSize > 128 KB ? 128 KB : srcSize; /* speed relative to block */
break; break;
} }
case 32: /* ZSTD_decodeSeqHeaders */ case 32: /* ZSTD_decodeSeqHeaders */
{ if (g_zdc==NULL) g_zdc = ZSTD_createDCtx();
blockProperties_t bp; { blockProperties_t bp;
ZSTD_frameParams zfp;
const BYTE* ip = dstBuff; const BYTE* ip = dstBuff;
const BYTE* iend; const BYTE* iend;
size_t blockSize; size_t frameHeaderSize, cBlockSize;
ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1); /* it would be better to use direct block compression here */ ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1); /* it would be better to use direct block compression here */
ip += 5; /* Skip frame Header */ g_cSize = ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1);
blockSize = ZSTD_getcBlockSize(ip, dstBuffSize, &bp); /* Get 1st block type */ frameHeaderSize = ZSTD_getFrameParams(&zfp, dstBuff, ZSTD_frameHeaderSize_min);
if (bp.blockType != bt_compressed) 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"); DISPLAY("ZSTD_decodeSeqHeaders : impossible to test on this sample (not compressible)\n");
goto _cleanOut; goto _cleanOut;
} }
iend = ip + 3 + blockSize; /* End of first block */ iend = ip + 3 /* ZSTD_blockHeaderSize */ + cBlockSize; /* End of first block */
ip += 3; /* skip block header */ ip += 3 /* ZSTD_blockHeaderSize */; /* skip block header */
ip += ZSTD_decodeLiteralsBlock(g_dctxPtr, ip, iend-ip); /* skip literal segment */ ip += ZSTD_decodeLiteralsBlock(g_zdc, ip, iend-ip); /* skip literal segment */
g_cSize = iend-ip; g_cSize = iend-ip;
memcpy(buff2, ip, g_cSize); /* copy rest of block (it starts by SeqHeader) */ memcpy(buff2, ip, g_cSize); /* copy rest of block (it starts by SeqHeader) */
srcSize = srcSize > 128 KB ? 128 KB : srcSize; /* speed relative to block */ srcSize = srcSize > 128 KB ? 128 KB : srcSize; /* speed relative to block */
break; break;
} }
case 41 :
if (g_zbcc==NULL) g_zbcc = ZBUFF_createCCtx();
break;
case 42 :
if (g_zbdc==NULL) g_zbdc = ZBUFF_createDCtx();
g_cSize = ZSTD_compress(buff2, dstBuffSize, src, srcSize, 1);
break;
/* test functions */ /* test functions */
/* by convention, test functions can be added > 100 */ /* by convention, test functions can be added > 100 */
@ -340,53 +378,44 @@ size_t benchMem(void* src, size_t srcSize, U32 benchNb)
{ size_t i; for (i=0; i<dstBuffSize; i++) dstBuff[i]=(BYTE)i; } /* warming up memory */ { size_t i; for (i=0; i<dstBuffSize; i++) dstBuff[i]=(BYTE)i; } /* warming up memory */
for (loopNb = 1; loopNb <= nbIterations; loopNb++) { U32 loopNb;
{ for (loopNb = 1; loopNb <= g_nbIterations; loopNb++) {
clock_t const timeLoop = TIMELOOP_S * CLOCKS_PER_SEC;
clock_t clockStart;
U32 nbRounds;
size_t benchResult=0;
double averageTime; double averageTime;
int milliTime;
U32 nbRounds=0;
DISPLAY("%2i- %-30.30s : \r", loopNb, benchName); DISPLAY("%2i- %-30.30s : \r", loopNb, benchName);
milliTime = BMK_GetMilliStart(); clockStart = clock();
while(BMK_GetMilliStart() == milliTime); while (clock() == clockStart);
milliTime = BMK_GetMilliStart(); clockStart = clock();
while(BMK_GetMilliSpan(milliTime) < TIMELOOP) for (nbRounds=0; BMK_clockSpan(clockStart) < timeLoop; nbRounds++) {
{ benchResult = benchFunction(dstBuff, dstBuffSize, buff2, src, srcSize);
errorCode = benchFunction(dstBuff, dstBuffSize, buff2, src, srcSize); if (ZSTD_isError(benchResult)) { DISPLAY("ERROR ! %s() => %s !! \n", benchName, ZSTD_getErrorName(benchResult)); exit(1); }
if (ZSTD_isError(errorCode)) { DISPLAY("ERROR ! %s() => %s !! \n", benchName, ZSTD_getErrorName(errorCode)); exit(1); }
nbRounds++;
} }
milliTime = BMK_GetMilliSpan(milliTime); averageTime = (((double)BMK_clockSpan(clockStart)) / CLOCKS_PER_SEC) / nbRounds;
averageTime = (double)milliTime / nbRounds;
if (averageTime < bestTime) bestTime = averageTime; if (averageTime < bestTime) bestTime = averageTime;
DISPLAY("%2i- %-30.30s : %7.1f MB/s (%9u)\r", loopNb, benchName, (double)srcSize / bestTime / 1000., (U32)errorCode); DISPLAY("%2i- %-30.30s : %7.1f MB/s (%9u)\r", loopNb, benchName, (double)srcSize / (1 MB) / bestTime, (U32)benchResult);
} }}
DISPLAY("%2u\n", benchNb);
DISPLAY("%2u- %-30.30s : %7.1f MB/s (%9u)\n", benchNb, benchName, (double)srcSize / bestTime / 1000., (U32)errorCode);
_cleanOut: _cleanOut:
free(dstBuff); free(dstBuff);
free(buff2); free(buff2);
ZSTD_freeDCtx(g_dctxPtr);
return 0; return 0;
} }
int benchSample(U32 benchNb) static int benchSample(U32 benchNb)
{ {
char* origBuff; size_t const benchedSize = g_sampleSize;
size_t benchedSize = sampleSize;
const char* name = "Sample 10MiB"; const char* name = "Sample 10MiB";
/* Allocation */ /* Allocation */
origBuff = (char*) malloc((size_t)benchedSize); void* origBuff = malloc(benchedSize);
if(!origBuff) if (!origBuff) { DISPLAY("\nError: not enough memory!\n"); return 12; }
{
DISPLAY("\nError: not enough memory!\n");
return 12;
}
/* Fill buffer */ /* Fill buffer */
RDG_genBuffer(origBuff, benchedSize, g_compressibility, 0.0, 0); RDG_genBuffer(origBuff, benchedSize, g_compressibility, 0.0, 0);
@ -404,58 +433,41 @@ int benchSample(U32 benchNb)
} }
int benchFiles(char** fileNamesTable, int nbFiles, U32 benchNb) static int benchFiles(const char** fileNamesTable, const int nbFiles, U32 benchNb)
{ {
int fileIdx=0;
/* Loop for each file */ /* Loop for each file */
while (fileIdx<nbFiles) int fileIdx;
{ for (fileIdx=0; fileIdx<nbFiles; fileIdx++) {
FILE* inFile; const char* inFileName = fileNamesTable[fileIdx];
char* inFileName; FILE* inFile = fopen( inFileName, "rb" );
U64 inFileSize; U64 inFileSize;
size_t benchedSize; size_t benchedSize;
size_t readSize; void* origBuff;
char* origBuff;
/* Check file existence */ /* Check file existence */
inFileName = fileNamesTable[fileIdx++]; if (inFile==NULL) { DISPLAY( "Pb opening %s\n", inFileName); return 11; }
inFile = fopen( inFileName, "rb" );
if (inFile==NULL)
{
DISPLAY( "Pb opening %s\n", inFileName);
return 11;
}
/* Memory allocation & restrictions */ /* Memory allocation & restrictions */
inFileSize = BMK_GetFileSize(inFileName); inFileSize = BMK_GetFileSize(inFileName);
benchedSize = (size_t) BMK_findMaxMem(inFileSize*3) / 3; benchedSize = BMK_findMaxMem(inFileSize*3) / 3;
if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize; if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize;
if (benchedSize < inFileSize) if (benchedSize < inFileSize)
{ DISPLAY("Not enough memory for '%s' full size; testing %u MB only...\n", inFileName, (U32)(benchedSize>>20));
DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", inFileName, (int)(benchedSize>>20));
}
/* Alloc */ /* Alloc */
origBuff = (char*) malloc((size_t)benchedSize); origBuff = malloc(benchedSize);
if(!origBuff) if (!origBuff) { DISPLAY("\nError: not enough memory!\n"); fclose(inFile); return 12; }
{
DISPLAY("\nError: not enough memory!\n");
fclose(inFile);
return 12;
}
/* Fill input buffer */ /* Fill input buffer */
DISPLAY("Loading %s... \r", inFileName); DISPLAY("Loading %s... \r", inFileName);
readSize = fread(origBuff, 1, benchedSize, inFile);
fclose(inFile);
if(readSize != benchedSize)
{ {
DISPLAY("\nError: problem reading file '%s' !! \n", inFileName); size_t readSize = fread(origBuff, 1, benchedSize, inFile);
free(origBuff); fclose(inFile);
return 13; if (readSize != benchedSize) {
} DISPLAY("\nError: problem reading file '%s' !! \n", inFileName);
free(origBuff);
return 13;
} }
/* bench */ /* bench */
DISPLAY("\r%79s\r", ""); DISPLAY("\r%79s\r", "");
@ -464,13 +476,15 @@ int benchFiles(char** fileNamesTable, int nbFiles, U32 benchNb)
benchMem(origBuff, benchedSize, benchNb); benchMem(origBuff, benchedSize, benchNb);
else else
for (benchNb=0; benchNb<100; benchNb++) benchMem(origBuff, benchedSize, benchNb); for (benchNb=0; benchNb<100; benchNb++) benchMem(origBuff, benchedSize, benchNb);
free(origBuff);
} }
return 0; return 0;
} }
int usage(char* exename) static int usage(const char* exename)
{ {
DISPLAY( "Usage :\n"); DISPLAY( "Usage :\n");
DISPLAY( " %s [arg] file1 file2 ... fileX\n", exename); DISPLAY( " %s [arg] file1 file2 ... fileX\n", exename);
@ -479,8 +493,9 @@ int usage(char* exename)
return 0; return 0;
} }
int usage_advanced(void) static int usage_advanced(const char* exename)
{ {
usage(exename);
DISPLAY( "\nAdvanced options :\n"); DISPLAY( "\nAdvanced options :\n");
DISPLAY( " -b# : test only function # \n"); DISPLAY( " -b# : test only function # \n");
DISPLAY( " -i# : iteration loops [1-9](default : %i)\n", NBLOOPS); DISPLAY( " -i# : iteration loops [1-9](default : %i)\n", NBLOOPS);
@ -488,45 +503,38 @@ int usage_advanced(void)
return 0; return 0;
} }
int badusage(char* exename) static int badusage(const char* exename)
{ {
DISPLAY("Wrong parameters\n"); DISPLAY("Wrong parameters\n");
usage(exename); usage(exename);
return 0; return 1;
} }
int main(int argc, char** argv) int main(int argc, const char** argv)
{ {
int i, int i, filenamesStart=0, result;
filenamesStart=0, const char* exename = argv[0];
result; const char* input_filename = NULL;
char* exename=argv[0];
char* input_filename=0;
U32 benchNb = 0, main_pause = 0; U32 benchNb = 0, main_pause = 0;
// Welcome message
DISPLAY(WELCOME_MESSAGE); DISPLAY(WELCOME_MESSAGE);
if (argc<1) return badusage(exename);
if (argc<1) { badusage(exename); return 1; } for(i=1; i<argc; i++) {
const char* argument = argv[i];
if(!argument) continue; /* Protection if argument empty */
for(i=1; i<argc; i++) /* Commands (note : aggregated commands are allowed) */
{ if (argument[0]=='-') {
char* argument = argv[i];
if(!argument) continue; // Protection if argument empty while (argument[1]!=0) {
argument++;
// Decode command (note : aggregated commands are allowed)
if (argument[0]=='-')
{
while (argument[1]!=0)
{
argument ++;
switch(argument[0]) switch(argument[0])
{ {
/* Display help on usage */ /* Display help on usage */
case 'h' : case 'h' :
case 'H': usage(exename); usage_advanced(); return 0; case 'H': return usage_advanced(exename);
/* Pause at the end (hidden option) */ /* Pause at the end (hidden option) */
case 'p': main_pause = 1; break; case 'p': main_pause = 1; break;
@ -534,8 +542,7 @@ int main(int argc, char** argv)
/* Select specific algorithm to bench */ /* Select specific algorithm to bench */
case 'b': case 'b':
benchNb = 0; benchNb = 0;
while ((argument[1]>= '0') && (argument[1]<= '9')) while ((argument[1]>= '0') && (argument[1]<= '9')) {
{
benchNb *= 10; benchNb *= 10;
benchNb += argument[1] - '0'; benchNb += argument[1] - '0';
argument++; argument++;
@ -544,20 +551,17 @@ int main(int argc, char** argv)
/* Modify Nb Iterations */ /* Modify Nb Iterations */
case 'i': case 'i':
if ((argument[1] >='0') && (argument[1] <='9')) if ((argument[1] >='0') && (argument[1] <='9')) {
{
int iters = argument[1] - '0'; int iters = argument[1] - '0';
BMK_SetNbIterations(iters); BMK_SetNbIterations(iters);
argument++; argument++;
} }
break; break;
/* Select specific algorithm to bench */ /* Select compressibility of synthetic sample */
case 'P': case 'P':
{ { U32 proba32 = 0;
U32 proba32 = 0; while ((argument[1]>= '0') && (argument[1]<= '9')) {
while ((argument[1]>= '0') && (argument[1]<= '9'))
{
proba32 *= 10; proba32 *= 10;
proba32 += argument[1] - '0'; proba32 += argument[1] - '0';
argument++; argument++;
@ -567,7 +571,7 @@ int main(int argc, char** argv)
break; break;
/* Unknown command */ /* Unknown command */
default : badusage(exename); return 1; default : return badusage(exename);
} }
} }
continue; continue;
@ -577,9 +581,10 @@ int main(int argc, char** argv)
if (!input_filename) { input_filename=argument; filenamesStart=i; continue; } if (!input_filename) { input_filename=argument; filenamesStart=i; continue; }
} }
if (filenamesStart==0) if (filenamesStart==0) /* no input file */
result = benchSample(benchNb); result = benchSample(benchNb);
else result = benchFiles(argv+filenamesStart, argc-filenamesStart, benchNb); else
result = benchFiles(argv+filenamesStart, argc-filenamesStart, benchNb);
if (main_pause) { int unused; printf("press enter...\n"); unused = getchar(); (void)unused; } if (main_pause) { int unused; printf("press enter...\n"); unused = getchar(); (void)unused; }

View File

@ -513,8 +513,7 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit
CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed"); CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed");
/* compression failure test : too small dest buffer */ /* compression failure test : too small dest buffer */
if (cSize > 3) if (cSize > 3) {
{
const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */ const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
const size_t tooSmallSize = cSize - missing; const size_t tooSmallSize = cSize - missing;
static const U32 endMark = 0x4DC2B1A9; static const U32 endMark = 0x4DC2B1A9;
@ -526,6 +525,13 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit
CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow"); CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow");
} }
/* decompression header test */
{ ZSTD_frameParams dParams;
size_t const check = ZSTD_getFrameParams(&dParams, cBuffer, cSize);
CHECK(ZSTD_isError(check), "Frame Parameters extraction failed");
CHECK(dParams.frameContentSize != sampleSize, "Frame content size incorrect");
}
/* successfull decompression tests*/ /* successfull decompression tests*/
dSupSize = (FUZ_rand(&lseed) & 1) ? 0 : (FUZ_rand(&lseed) & 31) + 1; dSupSize = (FUZ_rand(&lseed) & 1) ? 0 : (FUZ_rand(&lseed) & 31) + 1;
dSize = ZSTD_decompress(dstBuffer, sampleSize + dSupSize, cBuffer, cSize); dSize = ZSTD_decompress(dstBuffer, sampleSize + dSupSize, cBuffer, cSize);

View File

@ -36,7 +36,10 @@ $ZSTD --decompress tmpCompressed --stdout > tmpResult
$ZSTD -q tmp && die "overwrite check failed!" $ZSTD -q tmp && die "overwrite check failed!"
$ZSTD -q -f tmp $ZSTD -q -f tmp
$ZSTD -q --force tmp $ZSTD -q --force tmp
$ZSTD -df tmp && die "should have refused : wrong extension"
cp tmp tmp2.zst
$ZSTD -df tmp2.zst && die "should have failed : wrong format"
rm tmp2.zst
echo "\n**** frame concatenation **** " echo "\n**** frame concatenation **** "

View File

@ -132,6 +132,7 @@ static int usage_advanced(const char* programName)
DISPLAY( " -v : verbose mode\n"); DISPLAY( " -v : verbose mode\n");
DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n"); DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n");
DISPLAY( " -c : force write to standard output, even if it is the console\n"); DISPLAY( " -c : force write to standard output, even if it is the console\n");
DISPLAY( "--ultra : enable ultra modes (requires more memory to decompress)\n");
#ifndef ZSTD_NODICT #ifndef ZSTD_NODICT
DISPLAY( "Dictionary builder :\n"); DISPLAY( "Dictionary builder :\n");
DISPLAY( "--train : create a dictionary from a training set of files \n"); DISPLAY( "--train : create a dictionary from a training set of files \n");
@ -220,6 +221,7 @@ int main(int argCount, const char** argv)
if (!strcmp(argument, "--train")) { dictBuild=1; outFileName=g_defaultDictName; continue; } if (!strcmp(argument, "--train")) { dictBuild=1; outFileName=g_defaultDictName; continue; }
if (!strcmp(argument, "--maxdict")) { nextArgumentIsMaxDict=1; continue; } if (!strcmp(argument, "--maxdict")) { nextArgumentIsMaxDict=1; continue; }
if (!strcmp(argument, "--keep")) { continue; } /* does nothing, since preserving input is default; for gzip/xz compatibility */ if (!strcmp(argument, "--keep")) { continue; } /* does nothing, since preserving input is default; for gzip/xz compatibility */
if (!strcmp(argument, "--ultra")) { FIO_setMaxWLog(0); continue; }
/* '-' means stdin/stdout */ /* '-' means stdin/stdout */
if (!strcmp(argument, "-")){ if (!strcmp(argument, "-")){

View File

@ -161,6 +161,7 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\..\lib\fse.c" /> <ClCompile Include="..\..\..\lib\fse.c" />
<ClCompile Include="..\..\..\lib\huff0.c" /> <ClCompile Include="..\..\..\lib\huff0.c" />
<ClCompile Include="..\..\..\lib\zbuff.c" />
<ClCompile Include="..\..\..\lib\zstd_compress.c" /> <ClCompile Include="..\..\..\lib\zstd_compress.c" />
<ClCompile Include="..\..\..\lib\zstd_decompress.c" /> <ClCompile Include="..\..\..\lib\zstd_decompress.c" />
<ClCompile Include="..\..\..\programs\datagen.c" /> <ClCompile Include="..\..\..\programs\datagen.c" />
@ -175,6 +176,8 @@
<ClInclude Include="..\..\..\lib\legacy\zstd_v01.h" /> <ClInclude Include="..\..\..\lib\legacy\zstd_v01.h" />
<ClInclude Include="..\..\..\lib\legacy\zstd_v02.h" /> <ClInclude Include="..\..\..\lib\legacy\zstd_v02.h" />
<ClInclude Include="..\..\..\lib\legacy\zstd_v03.h" /> <ClInclude Include="..\..\..\lib\legacy\zstd_v03.h" />
<ClInclude Include="..\..\..\lib\zbuff.h" />
<ClInclude Include="..\..\..\lib\zbuff_static.h" />
<ClInclude Include="..\..\..\lib\zstd.h" /> <ClInclude Include="..\..\..\lib\zstd.h" />
<ClInclude Include="..\..\..\lib\zstd_static.h" /> <ClInclude Include="..\..\..\lib\zstd_static.h" />
<ClInclude Include="..\..\..\programs\datagen.h" /> <ClInclude Include="..\..\..\programs\datagen.h" />

View File

@ -33,6 +33,9 @@
<ClCompile Include="..\..\..\lib\zstd_decompress.c"> <ClCompile Include="..\..\..\lib\zstd_decompress.c">
<Filter>Fichiers sources</Filter> <Filter>Fichiers sources</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\lib\zbuff.c">
<Filter>Fichiers sources</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\lib\fse.h"> <ClInclude Include="..\..\..\lib\fse.h">
@ -68,5 +71,11 @@
<ClInclude Include="..\..\..\lib\legacy\zstd_v03.h"> <ClInclude Include="..\..\..\lib\legacy\zstd_v03.h">
<Filter>Fichiers d%27en-tête</Filter> <Filter>Fichiers d%27en-tête</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\lib\zbuff.h">
<Filter>Fichiers d%27en-tête</Filter>
</ClInclude>
<ClInclude Include="..\..\..\lib\zbuff_static.h">
<Filter>Fichiers d%27en-tête</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>