diff --git a/Makefile b/Makefile index 93d5e0528..494f59dca 100644 --- a/Makefile +++ b/Makefile @@ -89,9 +89,8 @@ gpptest: clean $(MAKE) all CC=g++ CFLAGS="-O3 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror" armtest: clean -# $(MAKE) -C $(ZSTDDIR) all CC=arm-linux-gnueabi-gcc MOREFLAGS="-Werror" $(MAKE) -C $(PRGDIR) datagen # use native, faster - $(MAKE) -C $(PRGDIR) test CC=arm-linux-gnueabi-gcc ZSTDRTTEST= MOREFLAGS=-static # MOREFLAGS="-Werror -static" + $(MAKE) -C $(PRGDIR) test CC=arm-linux-gnueabi-gcc ZSTDRTTEST= MOREFLAGS="-Werror -static" # for Travis CI arminstall: clean @@ -105,7 +104,7 @@ armtest-w-install: clean arminstall armtest ppctest: clean $(MAKE) -C $(PRGDIR) datagen # use native, faster - $(MAKE) -C $(PRGDIR) test CC=powerpc-linux-gnu-gcc ZSTDRTTEST= MOREFLAGS=-static # MOREFLAGS="-Werror -static" + $(MAKE) -C $(PRGDIR) test CC=powerpc-linux-gnu-gcc ZSTDRTTEST= MOREFLAGS="-Werror -static" # for Travis CI ppcinstall: clean diff --git a/lib/bitstream.h b/lib/bitstream.h index e12379306..fd114e55a 100644 --- a/lib/bitstream.h +++ b/lib/bitstream.h @@ -53,6 +53,14 @@ extern "C" { #include "error_private.h" /* error codes and messages */ +/*========================================= +* Target specific +=========================================*/ +#if defined(__BMI__) && defined(__GNUC__) +# include /* support for bextr (experimental) */ +#endif + + /*-****************************************** * bitStream encoding API (write forward) ********************************************/ @@ -122,7 +130,7 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); * Local register is explicitly reloaded from memory by the BIT_reloadDStream() method. * A reload guarantee a minimum of ((8*sizeof(size_t))-7) bits when its result is BIT_DStream_unfinished. * Otherwise, it can be less than that, so proceed accordingly. -* Checking if DStream has reached its end can be performed with BIT_endOfDStream() +* Checking if DStream has reached its end can be performed with BIT_endOfDStream(). */ @@ -141,7 +149,7 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); /*-************************************************************** -* Helper functions +* Internal functions ****************************************************************/ MEM_STATIC unsigned BIT_highbit32 (register U32 val) { @@ -165,6 +173,9 @@ MEM_STATIC unsigned BIT_highbit32 (register U32 val) # endif } +/*===== Local Constants =====*/ +static const unsigned BIT_mask[] = { 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF }; /* up to 26 bits */ + /*-************************************************************** * bitStream encoding @@ -189,8 +200,7 @@ MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* startPtr, size_t ds Does not check for register overflow ! */ MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits) { - static const unsigned mask[] = { 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF }; /* up to 26 bits */ - bitC->bitContainer |= (value & mask[nbBits]) << bitC->bitPos; + bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos; bitC->bitPos += nbBits; } @@ -206,7 +216,7 @@ MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBi * unsafe version; does not check buffer overflow */ MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC) { - size_t nbBytes = bitC->bitPos >> 3; + size_t const nbBytes = bitC->bitPos >> 3; MEM_writeLEST(bitC->ptr, bitC->bitContainer); bitC->ptr += nbBytes; bitC->bitPos &= 7; @@ -218,7 +228,7 @@ MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC) * note : does not signal buffer overflow. This will be revealed later on using BIT_closeCStream() */ MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC) { - size_t nbBytes = bitC->bitPos >> 3; + size_t const nbBytes = bitC->bitPos >> 3; MEM_writeLEST(bitC->ptr, bitC->bitContainer); bitC->ptr += nbBytes; if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr; @@ -246,8 +256,7 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC) /*! BIT_initDStream() : * Initialize a BIT_DStream_t. * `bitD` : a pointer to an already allocated BIT_DStream_t structure. -* `srcBuffer` must point at the beginning of a bitStream. -* `srcSize` must be the exact size of the bitStream, in bytes. +* `srcSize` must be the *exact* size of the bitStream, in bytes. * @return : size of stream (== srcSize) or an errorCode if a problem is detected */ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize) @@ -255,15 +264,13 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } if (srcSize >= sizeof(size_t)) { /* normal case */ - U32 contain32; bitD->start = (const char*)srcBuffer; bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(size_t); bitD->bitContainer = MEM_readLEST(bitD->ptr); - contain32 = ((const BYTE*)srcBuffer)[srcSize-1]; - if (contain32 == 0) return ERROR(GENERIC); /* endMark not present */ - bitD->bitsConsumed = 8 - BIT_highbit32(contain32); + { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; + if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ + bitD->bitsConsumed = 8 - BIT_highbit32(lastByte); } } else { - U32 contain32; bitD->start = (const char*)srcBuffer; bitD->ptr = bitD->start; bitD->bitContainer = *(const BYTE*)(bitD->start); @@ -277,15 +284,34 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si case 2: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[1]) << 8; default:; } - contain32 = ((const BYTE*)srcBuffer)[srcSize-1]; - if (contain32 == 0) return ERROR(GENERIC); /* endMark not present */ - bitD->bitsConsumed = 8 - BIT_highbit32(contain32); + { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; + if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ + bitD->bitsConsumed = 8 - BIT_highbit32(lastByte); } bitD->bitsConsumed += (U32)(sizeof(size_t) - srcSize)*8; } return srcSize; } +MEM_STATIC size_t BIT_getUpperBits(size_t bitD, U32 const start) +{ + return bitD >> start; +} + +MEM_STATIC size_t BIT_getMiddleBits(size_t bitD, U32 const nbBits, U32 const start) +{ +#if defined(__BMI__) && defined(__GNUC__) /* experimental */ + return __builtin_ia32_bextr_u64(bitD, (nbBits<<8) | start ); +#else + return (bitD >> start) & BIT_mask[nbBits]; +#endif +} + +MEM_STATIC size_t BIT_getLowerBits(size_t bitD, U32 const nbBits) +{ + return bitD & BIT_mask[nbBits]; +} + /*! BIT_lookBits() : * Provides next n bits from local register. * local register is not modified (bits are still present for next read/look). @@ -293,15 +319,19 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si * On 64-bits, maxNbBits==56. * @return : value extracted */ -MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits) + MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits) { +#if defined(__BMI__) && defined(__GNUC__) /* experimental */ + return __builtin_ia32_bextr_u64(bitD->bitContainer, (nbBits<<8) | (64 - bitD->bitsConsumed - nbBits) ); +#else U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1; return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask-nbBits) & bitMask); +#endif } /*! BIT_lookBitsFast() : * unsafe version; only works only if nbBits >= 1 */ -MEM_STATIC size_t BIT_lookBitsFast(BIT_DStream_t* bitD, U32 nbBits) +MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits) { U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1; return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask+1)-nbBits) & bitMask); @@ -313,13 +343,13 @@ MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) } /*! BIT_readBits() : - * Read next n bits from local register. - * pay attention to not read more than nbBits contained into local register. + * Read (consume) next n bits from local register and update. + * Pay attention to not read more than nbBits contained into local register. * @return : extracted value. */ MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) { - size_t value = BIT_lookBits(bitD, nbBits); + size_t const value = BIT_lookBits(bitD, nbBits); BIT_skipBits(bitD, nbBits); return value; } @@ -328,7 +358,7 @@ MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) * unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits) { - size_t value = BIT_lookBitsFast(bitD, nbBits); + size_t const value = BIT_lookBitsFast(bitD, nbBits); BIT_skipBits(bitD, nbBits); return value; } diff --git a/lib/error_private.h b/lib/error_private.h index ff0b829fc..7bd03065b 100644 --- a/lib/error_private.h +++ b/lib/error_private.h @@ -95,6 +95,7 @@ ERR_STATIC const char* ERR_getErrorName(size_t code) case PREFIX(prefix_unknown): return "Unknown frame descriptor"; case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; case PREFIX(frameParameter_unsupportedBy32bits): return "Frame parameter unsupported in 32-bits mode"; + case PREFIX(compressionParameter_unsupported): return "Compression parameter is out of bound"; case PREFIX(init_missing): return "Context should be init first"; case PREFIX(memory_allocation): return "Allocation error : not enough memory"; case PREFIX(stage_wrong): return "Operation not authorized at current processing stage"; diff --git a/lib/error_public.h b/lib/error_public.h index 073b8c6a9..6fcf802e0 100644 --- a/lib/error_public.h +++ b/lib/error_public.h @@ -47,6 +47,7 @@ typedef enum { ZSTD_error_prefix_unknown, ZSTD_error_frameParameter_unsupported, ZSTD_error_frameParameter_unsupportedBy32bits, + ZSTD_error_compressionParameter_unsupported, ZSTD_error_init_missing, ZSTD_error_memory_allocation, ZSTD_error_stage_wrong, diff --git a/lib/fse.c b/lib/fse.c index 291e64192..63898ab1c 100644 --- a/lib/fse.c +++ b/lib/fse.c @@ -145,21 +145,18 @@ static U32 FSE_tableStep(U32 tableSize) { return (tableSize>>1) + (tableSize>>3) size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) { - const unsigned tableSize = 1 << tableLog; - const unsigned tableMask = tableSize - 1; + U32 const tableSize = 1 << tableLog; + U32 const tableMask = tableSize - 1; void* const ptr = ct; U16* const tableU16 = ( (U16*) ptr) + 2; void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableLog ? tableSize>>1 : 1) ; FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT); - const unsigned step = FSE_tableStep(tableSize); - unsigned cumul[FSE_MAX_SYMBOL_VALUE+2]; - U32 position = 0; + U32 const step = FSE_tableStep(tableSize); + U32 cumul[FSE_MAX_SYMBOL_VALUE+2]; FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE]; /* memset() is not necessary, even if static analyzer complain about it */ U32 highThreshold = tableSize-1; - unsigned symbol; - unsigned i; - /* header */ + /* CTable header */ tableU16[-2] = (U16) tableLog; tableU16[-1] = (U16) maxSymbolValue; @@ -167,42 +164,44 @@ size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */ /* symbol start positions */ - cumul[0] = 0; - for (i=1; i<=maxSymbolValue+1; i++) { - if (normalizedCounter[i-1]==-1) { /* Low proba symbol */ - cumul[i] = cumul[i-1] + 1; - tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(i-1); - } else { - cumul[i] = cumul[i-1] + normalizedCounter[i-1]; - } } - cumul[maxSymbolValue+1] = tableSize+1; - - /* Spread symbols */ - for (symbol=0; symbol<=maxSymbolValue; symbol++) { - int nbOccurences; - for (nbOccurences=0; nbOccurences highThreshold) position = (position + step) & tableMask; /* Low proba area */ - } } - - if (position!=0) return ERROR(GENERIC); /* Must have gone through all positions */ - - /* Build table */ - for (i=0; i highThreshold) position = (position + step) & tableMask; /* Low proba area */ + } } + if (position!=0) return ERROR(GENERIC); /* Must have gone through all positions */ + } + + /* Build table */ + { U32 u; for (u=0; u highThreshold) position = (position + step) & tableMask; /* lowprob area */ - } } - - if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ + { U32 position = 0; + for (s=0; s<=maxSymbolValue; s++) { + int i; + for (i=0; i highThreshold) position = (position + step) & tableMask; /* lowprob area */ + } } + if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ + } /* Build Decoding table */ - { - U32 i; - for (i=0; i>= 16; bitCount -= 16; } } - { - short count = normalizedCounter[charnum++]; + { short count = normalizedCounter[charnum++]; const short max = (short)((2*threshold-1)-remaining); remaining -= FSE_abs(count); if (remaining<1) return ERROR(GENERIC); @@ -465,8 +462,7 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t else bitStream >>= 2; } - { - short const max = (short)((2*threshold-1)-remaining); + { short const max = (short)((2*threshold-1)-remaining); short count; if ((bitStream & (threshold-1)) < (U32)max) { @@ -509,11 +505,11 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t * Counting histogram ****************************************************************/ /*! FSE_count_simple - This function just counts byte values within @src, - and store the histogram into @count. - This function is unsafe : it doesn't check that all values within @src can fit into @count. - For this reason, prefer using a table @count with 256 elements. - @return : highest count for a single element + This function just counts byte values within `src`, + and store the histogram into table `count`. + This function is unsafe : it doesn't check that all values within `src` can fit into `count`. + For this reason, prefer using a table `count` with 256 elements. + @return : count of most numerous element */ static size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize) @@ -522,7 +518,6 @@ static size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, const BYTE* const end = ip + srcSize; unsigned maxSymbolValue = *maxSymbolValuePtr; unsigned max=0; - U32 s; memset(count, 0, (maxSymbolValue+1)*sizeof(*count)); if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; } @@ -532,7 +527,7 @@ static size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, while (!count[maxSymbolValue]) maxSymbolValue--; *maxSymbolValuePtr = maxSymbolValue; - for (s=0; s<=maxSymbolValue; s++) if (count[s] > max) max = count[s]; + { U32 s; for (s=0; s<=maxSymbolValue; s++) if (count[s] > max) max = count[s]; } return (size_t)max; } @@ -546,7 +541,6 @@ static size_t FSE_count_parallel(unsigned* count, unsigned* maxSymbolValuePtr, const BYTE* const iend = ip+sourceSize; unsigned maxSymbolValue = *maxSymbolValuePtr; unsigned max=0; - U32 s; U32 Counting1[256] = { 0 }; U32 Counting2[256] = { 0 }; @@ -561,8 +555,8 @@ static size_t FSE_count_parallel(unsigned* count, unsigned* maxSymbolValuePtr, } if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */ - { /* by stripes of 16 bytes */ - U32 cached = MEM_read32(ip); ip += 4; + /* by stripes of 16 bytes */ + { U32 cached = MEM_read32(ip); ip += 4; while (ip < iend-15) { U32 c = cached; cached = MEM_read32(ip); ip += 4; Counting1[(BYTE) c ]++; @@ -592,15 +586,15 @@ static size_t FSE_count_parallel(unsigned* count, unsigned* maxSymbolValuePtr, while (ipmaxSymbolValue; s--) { + U32 s; for (s=255; s>maxSymbolValue; s--) { Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s]; if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall); } } - for (s=0; s<=maxSymbolValue; s++) { + { U32 s; for (s=0; s<=maxSymbolValue; s++) { count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s]; if (count[s] > max) max = count[s]; - } + }} while (!count[maxSymbolValue]) maxSymbolValue--; *maxSymbolValuePtr = maxSymbolValue; @@ -634,7 +628,7 @@ size_t FSE_count(unsigned* count, unsigned* maxSymbolValuePtr, `U16 maxSymbolValue;` `U16 nextStateNumber[1 << tableLog];` // This size is variable `FSE_symbolCompressionTransform symbolTT[maxSymbolValue+1];` // This size is variable -Allocation is manual, since C standard does not support variable-size structures. +Allocation is manual (C standard does not support variable-size structures). */ size_t FSE_sizeof_CTable (unsigned maxSymbolValue, unsigned tableLog) @@ -730,7 +724,7 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, /* all values are pretty poor; probably incompressible data (should have already been detected); find max, then give all remaining points to max */ - U32 maxV = 0, maxC =0; + U32 maxV = 0, maxC = 0; for (s=0; s<=maxSymbolValue; s++) if (count[s] > maxC) maxV=s, maxC=count[s]; norm[maxV] += (short)ToDistribute; @@ -768,8 +762,7 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog, if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported size */ if (tableLog < FSE_minTableLog(total, maxSymbolValue)) return ERROR(GENERIC); /* Too small tableLog, compression potentially impossible */ - { - U32 const rtbTable[] = { 0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 }; + { U32 const rtbTable[] = { 0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 }; U64 const scale = 62 - tableLog; U64 const step = ((U64)1<<62) / total; /* <== here, one division ! */ U64 const vStep = 1ULL<<(scale-20); @@ -845,13 +838,11 @@ size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits) tableU16[s] = (U16)(tableSize + s); /* Build Symbol Transformation Table */ - { - const U32 deltaNbBits = (nbBits << 16) - (1 << nbBits); + { const U32 deltaNbBits = (nbBits << 16) - (1 << nbBits); for (s=0; s<=maxSymbolValue; s++) { symbolTT[s].deltaNbBits = deltaNbBits; symbolTT[s].deltaFindState = s-1; - } - } + } } return 0; } @@ -887,15 +878,13 @@ static size_t FSE_compress_usingCTable_generic (void* dst, size_t dstSize, const BYTE* const istart = (const BYTE*) src; const BYTE* const iend = istart + srcSize; const BYTE* ip=iend; - - size_t errorCode; BIT_CStream_t bitC; FSE_CState_t CState1, CState2; /* init */ if (srcSize <= 2) return 0; - errorCode = BIT_initCStream(&bitC, dst, dstSize); - if (FSE_isError(errorCode)) return 0; + { size_t const errorCode = BIT_initCStream(&bitC, dst, dstSize); + if (FSE_isError(errorCode)) return 0; } #define FSE_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s)) @@ -918,8 +907,7 @@ static size_t FSE_compress_usingCTable_generic (void* dst, size_t dstSize, } /* 2 or 4 encoding per loop */ - for ( ; ip>istart ; ) - { + for ( ; ip>istart ; ) { FSE_encodeSymbol(&bitC, &CState2, *--ip); if (sizeof(bitC.bitContainer)*8 < FSE_MAX_TABLELOG*2+7 ) /* this test must be static */ diff --git a/lib/fse_static.h b/lib/fse_static.h index ca303db84..f3c3d44e0 100644 --- a/lib/fse_static.h +++ b/lib/fse_static.h @@ -267,7 +267,7 @@ MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePt BIT_flushBits(bitC); } -/* decompression */ +/*<===== Decompression =====>*/ typedef struct { U16 tableLog; @@ -290,34 +290,39 @@ MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, con DStatePtr->table = dt + 1; } -MEM_STATIC size_t FSE_getStateValue(FSE_DState_t* DStatePtr) +MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr) { - return DStatePtr->state; + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + return DInfo.symbol; } -MEM_STATIC BYTE FSE_peakSymbol(FSE_DState_t* DStatePtr) +MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) { - const FSE_decode_t DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; - return DInfo.symbol; + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + size_t const lowBits = BIT_readBits(bitD, nbBits); + DStatePtr->state = DInfo.newState + lowBits; } MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) { - const FSE_decode_t DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; - const U32 nbBits = DInfo.nbBits; - BYTE symbol = DInfo.symbol; - size_t lowBits = BIT_readBits(bitD, nbBits); + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + BYTE const symbol = DInfo.symbol; + size_t const lowBits = BIT_readBits(bitD, nbBits); DStatePtr->state = DInfo.newState + lowBits; return symbol; } +/*! FSE_decodeSymbolFast() : + unsafe, only works if no symbol has a probability > 50% */ MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) { - const FSE_decode_t DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; - const U32 nbBits = DInfo.nbBits; - BYTE symbol = DInfo.symbol; - size_t lowBits = BIT_readBitsFast(bitD, nbBits); + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + BYTE const symbol = DInfo.symbol; + size_t const lowBits = BIT_readBitsFast(bitD, nbBits); DStatePtr->state = DInfo.newState + lowBits; return symbol; diff --git a/lib/zbuff.c b/lib/zbuff.c index 386b47d5a..b0225e857 100644 --- a/lib/zbuff.c +++ b/lib/zbuff.c @@ -26,14 +26,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd - - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c + - zstd homepage : http://www.zstd.net/ */ -/* The objects defined into this file should be considered experimental. - * They are not labelled stable, as their prototype may change in the future. - * You can use them for tests, provide feedback, or if you can endure risk of future changes. - */ /* ************************************* * Dependencies @@ -124,21 +119,20 @@ size_t ZBUFF_freeCCtx(ZBUFF_CCtx* zbc) /* *** Initialization *** */ -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, U64 pledgedSrcSize) { - size_t neededInBuffSize; - - ZSTD_validateParams(¶ms); - neededInBuffSize = (size_t)1 << params.windowLog; - /* allocate buffers */ - if (zbc->inBuffSize < neededInBuffSize) { - zbc->inBuffSize = neededInBuffSize; - free(zbc->inBuff); /* should not be necessary */ - zbc->inBuff = (char*)malloc(neededInBuffSize); - if (zbc->inBuff == NULL) return ERROR(memory_allocation); + { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog; + if (zbc->inBuffSize < neededInBuffSize) { + zbc->inBuffSize = neededInBuffSize; + free(zbc->inBuff); /* should not be necessary */ + zbc->inBuff = (char*)malloc(neededInBuffSize); + if (zbc->inBuff == NULL) return ERROR(memory_allocation); + } + zbc->blockSize = MIN(ZSTD_BLOCKSIZE_MAX, neededInBuffSize/2); } - zbc->blockSize = MIN(ZSTD_BLOCKSIZE_MAX, zbc->inBuffSize); if (zbc->outBuffSize < ZSTD_compressBound(zbc->blockSize)+1) { zbc->outBuffSize = ZSTD_compressBound(zbc->blockSize)+1; free(zbc->outBuff); /* should not be necessary */ @@ -146,26 +140,30 @@ size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, const void* dict, size_t dic if (zbc->outBuff == NULL) return ERROR(memory_allocation); } - zbc->outBuffContentSize = ZSTD_compressBegin_advanced(zbc->zc, dict, dictSize, params); - if (ZSTD_isError(zbc->outBuffContentSize)) return zbc->outBuffContentSize; + { size_t const errorCode = ZSTD_compressBegin_advanced(zbc->zc, dict, dictSize, params, pledgedSrcSize); + if (ZSTD_isError(errorCode)) return errorCode; } zbc->inToCompress = 0; zbc->inBuffPos = 0; zbc->inBuffTarget = zbc->blockSize; zbc->outBuffFlushedSize = 0; - zbc->stage = ZBUFFcs_flush; /* starts by flushing the header */ + zbc->stage = ZBUFFcs_load; return 0; /* ready to go */ } + +size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* zbc, const void* dict, size_t dictSize, int compressionLevel) +{ + ZSTD_parameters params; + params.cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); + params.fParams.contentSizeFlag = 0; + ZSTD_adjustCParams(¶ms.cParams, 0, dictSize); + return ZBUFF_compressInit_advanced(zbc, dict, dictSize, params, 0); +} + size_t ZBUFF_compressInit(ZBUFF_CCtx* zbc, int compressionLevel) { - return ZBUFF_compressInit_advanced(zbc, NULL, 0, ZSTD_getParams(compressionLevel, 0)); -} - - -ZSTDLIB_API size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* zbc, const void* dict, size_t dictSize, int compressionLevel) -{ - return ZBUFF_compressInit_advanced(zbc, dict, dictSize, ZSTD_getParams(compressionLevel, 0)); + return ZBUFF_compressInitDictionary(zbc, NULL, 0, compressionLevel); } @@ -185,11 +183,11 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc, { U32 notDone = 1; const char* const istart = (const char*)src; - const char* ip = istart; const char* const iend = istart + *srcSizePtr; + const char* ip = istart; char* const ostart = (char*)dst; - char* op = ostart; char* const oend = ostart + *dstCapacityPtr; + char* op = ostart; while (notDone) { switch(zbc->stage) @@ -198,19 +196,17 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc, case ZBUFFcs_load: /* complete inBuffer */ - { - size_t toLoad = zbc->inBuffTarget - zbc->inBuffPos; - size_t loaded = ZBUFF_limitCopy(zbc->inBuff + zbc->inBuffPos, toLoad, ip, iend-ip); + { size_t const toLoad = zbc->inBuffTarget - zbc->inBuffPos; + size_t const loaded = ZBUFF_limitCopy(zbc->inBuff + zbc->inBuffPos, toLoad, ip, iend-ip); zbc->inBuffPos += loaded; ip += loaded; if ( (zbc->inBuffPos==zbc->inToCompress) || (!flush && (toLoad != loaded)) ) { notDone = 0; break; /* not enough input to get a full block : stop there, wait for more */ } } /* compress current block (note : this stage cannot be stopped in the middle) */ - { - void* cDst; + { void* cDst; size_t cSize; - size_t iSize = zbc->inBuffPos - zbc->inToCompress; + size_t const iSize = zbc->inBuffPos - zbc->inToCompress; size_t oSize = oend-op; if (oSize >= ZSTD_compressBound(iSize)) cDst = op; /* compress directly into output buffer (avoid flush stage) */ @@ -221,20 +217,18 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc, /* prepare next block */ zbc->inBuffTarget = zbc->inBuffPos + zbc->blockSize; if (zbc->inBuffTarget > zbc->inBuffSize) - { zbc->inBuffPos = 0; zbc->inBuffTarget = zbc->blockSize; } /* note : inBuffSize >= blockSize */ + zbc->inBuffPos = 0, zbc->inBuffTarget = zbc->blockSize; /* note : inBuffSize >= blockSize */ zbc->inToCompress = zbc->inBuffPos; if (cDst == op) { op += cSize; break; } /* no need to flush */ zbc->outBuffContentSize = cSize; zbc->outBuffFlushedSize = 0; - zbc->stage = ZBUFFcs_flush; - // break; /* flush stage follows */ + zbc->stage = ZBUFFcs_flush; /* continue to flush stage */ } case ZBUFFcs_flush: /* flush into dst */ - { - size_t toFlush = zbc->outBuffContentSize - zbc->outBuffFlushedSize; - size_t flushed = ZBUFF_limitCopy(op, oend-op, zbc->outBuff + zbc->outBuffFlushedSize, toFlush); + { size_t const toFlush = zbc->outBuffContentSize - zbc->outBuffFlushedSize; + size_t const flushed = ZBUFF_limitCopy(op, oend-op, zbc->outBuff + zbc->outBuffFlushedSize, toFlush); op += flushed; zbc->outBuffFlushedSize += flushed; if (toFlush!=flushed) { notDone = 0; break; } /* not enough space within dst to store compressed block : stop there */ @@ -250,8 +244,7 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc, *srcSizePtr = ip - istart; *dstCapacityPtr = op - ostart; - { - size_t hintInSize = zbc->inBuffTarget - zbc->inBuffPos; + { size_t hintInSize = zbc->inBuffTarget - zbc->inBuffPos; if (hintInSize==0) hintInSize = zbc->blockSize; return hintInSize; } @@ -271,7 +264,7 @@ size_t ZBUFF_compressContinue(ZBUFF_CCtx* zbc, size_t ZBUFF_compressFlush(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr) { size_t srcSize = 0; - ZBUFF_compressContinue_generic(zbc, dst, dstCapacityPtr, &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 */ return zbc->outBuffContentSize - zbc->outBuffFlushedSize; } @@ -279,11 +272,11 @@ size_t ZBUFF_compressFlush(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr) size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr) { BYTE* const ostart = (BYTE*)dst; - BYTE* op = ostart; BYTE* const oend = ostart + *dstCapacityPtr; + BYTE* op = ostart; size_t outSize = *dstCapacityPtr; size_t epilogueSize, remaining; - ZBUFF_compressFlush(zbc, dst, &outSize); /* flush any remaining inBuff */ + ZBUFF_compressFlush(zbc, dst, &outSize); /* flush any remaining inBuff */ op += outSize; epilogueSize = ZSTD_compressEnd(zbc->zc, zbc->outBuff + zbc->outBuffContentSize, zbc->outBuffSize - zbc->outBuffContentSize); /* epilogue into outBuff */ zbc->outBuffContentSize += epilogueSize; @@ -291,7 +284,7 @@ size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr) zbc->stage = ZBUFFcs_flush; remaining = ZBUFF_compressFlush(zbc, op, &outSize); /* attempt to flush epilogue into dst */ 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 */ *dstCapacityPtr = op-ostart; /* tells how many bytes were written */ return remaining; } @@ -328,10 +321,11 @@ typedef enum { ZBUFFds_init, ZBUFFds_readHeader, struct ZBUFF_DCtx_s { ZSTD_DCtx* zc; ZSTD_frameParams fParams; - char* inBuff; + size_t blockSize; + char* inBuff; size_t inBuffSize; size_t inPos; - char* outBuff; + char* outBuff; size_t outBuffSize; size_t outStart; size_t outEnd; @@ -406,27 +400,26 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, return headerSize; } } - /* Frame header provides buffer sizes */ - { size_t const neededInSize = ZSTD_BLOCKSIZE_MAX; /* a block is never > ZSTD_BLOCKSIZE_MAX */ - if (zbc->inBuffSize < neededInSize) { + /* Frame header instruct buffer sizes */ + { size_t const blockSize = MIN(1 << zbc->fParams.windowLog, ZSTD_BLOCKSIZE_MAX); + zbc->blockSize = blockSize; + if (zbc->inBuffSize < blockSize) { free(zbc->inBuff); - zbc->inBuffSize = neededInSize; - zbc->inBuff = (char*)malloc(neededInSize); + zbc->inBuffSize = blockSize; + zbc->inBuff = (char*)malloc(blockSize); if (zbc->inBuff == NULL) return ERROR(memory_allocation); - } } - { - size_t const neededOutSize = (size_t)1 << zbc->fParams.windowLog; - if (zbc->outBuffSize < neededOutSize) { - free(zbc->outBuff); - zbc->outBuffSize = neededOutSize; - zbc->outBuff = (char*)malloc(neededOutSize); - if (zbc->outBuff == NULL) return ERROR(memory_allocation); - } } + } + { size_t const neededOutSize = ((size_t)1 << zbc->fParams.windowLog) + blockSize; + if (zbc->outBuffSize < neededOutSize) { + free(zbc->outBuff); + zbc->outBuffSize = neededOutSize; + zbc->outBuff = (char*)malloc(neededOutSize); + if (zbc->outBuff == NULL) return ERROR(memory_allocation); + } } } zbc->stage = ZBUFFds_read; case ZBUFFds_read: - { - size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc); + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc); if (neededInSize==0) { /* end of frame */ zbc->stage = ZBUFFds_init; notDone = 0; @@ -449,8 +442,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, } case ZBUFFds_load: - { - size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc); + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc); size_t const toLoad = neededInSize - zbc->inPos; /* should always be <= remaining space within inBuff */ size_t loadedSize; if (toLoad > zbc->inBuffSize - zbc->inPos) return ERROR(corruption_detected); /* should never happen */ @@ -458,8 +450,8 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, ip += loadedSize; zbc->inPos += loadedSize; if (loadedSize < toLoad) { notDone = 0; break; } /* not enough input, wait for more */ - { - size_t const decodedSize = ZSTD_decompressContinue(zbc->zc, + /* decode loaded input */ + { size_t const decodedSize = ZSTD_decompressContinue(zbc->zc, zbc->outBuff + zbc->outStart, zbc->outBuffSize - zbc->outStart, zbc->inBuff, neededInSize); if (ZSTD_isError(decodedSize)) return decodedSize; @@ -469,15 +461,15 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, zbc->stage = ZBUFFds_flush; // break; /* ZBUFFds_flush follows */ } } + case ZBUFFds_flush: - { - size_t const toFlushSize = zbc->outEnd - zbc->outStart; + { size_t const toFlushSize = zbc->outEnd - zbc->outStart; size_t const flushedSize = ZBUFF_limitCopy(op, oend-op, zbc->outBuff + zbc->outStart, toFlushSize); op += flushedSize; zbc->outStart += flushedSize; if (flushedSize == toFlushSize) { zbc->stage = ZBUFFds_read; - if (zbc->outStart + ZSTD_BLOCKSIZE_MAX > zbc->outBuffSize) + if (zbc->outStart + zbc->blockSize > zbc->outBuffSize) zbc->outStart = zbc->outEnd = 0; break; } @@ -491,8 +483,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, /* result */ *srcSizePtr = ip-istart; *dstCapacityPtr = op-ostart; - { - size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zbc->zc); + { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zbc->zc); if (nextSrcSizeHint > ZSTD_blockHeaderSize) nextSrcSizeHint+= ZSTD_blockHeaderSize; /* get following block header too */ nextSrcSizeHint -= zbc->inPos; /* already loaded*/ return nextSrcSizeHint; diff --git a/lib/zbuff.h b/lib/zbuff.h index 7a914a4a7..e2482054c 100644 --- a/lib/zbuff.h +++ b/lib/zbuff.h @@ -31,11 +31,6 @@ #ifndef ZSTD_BUFFERED_H #define ZSTD_BUFFERED_H -/* The objects defined into this file should be considered experimental. - * They are not considered stable, as their prototype may change in the future. - * You can use them for tests, provide feedback, or if you can endure risk of future changes. - */ - #if defined (__cplusplus) extern "C" { #endif @@ -89,12 +84,12 @@ ZSTDLIB_API size_t ZBUFF_compressEnd(ZBUFF_CCtx* cctx, void* dst, size_t* dstCap * *srcSizePtr and *dstCapacityPtr can be any size. * The function will report how many bytes were read or written within *srcSizePtr and *dstCapacityPtr. * Note that it may not consume the entire input, in which case it's up to the caller to present again remaining data. -* The content of @dst will be overwritten (up to *dstCapacityPtr) at each call, so save its content if it matters or change @dst . +* The content of `dst` will be overwritten (up to *dstCapacityPtr) at each 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 just a hint, to improve latency) * or an error code, which can be tested using ZBUFF_isError(). * * At any moment, it's possible to flush whatever data remains within buffer, using ZBUFF_compressFlush(). -* The nb of bytes written into @dst will be reported into *dstCapacityPtr. +* The nb of bytes written into `dst` will be reported into *dstCapacityPtr. * Note that the function cannot output more than *dstCapacityPtr, * therefore, some content might still be left into internal buffer if *dstCapacityPtr is too small. * @return : nb of bytes still present into internal buffer (0 if it's empty) @@ -139,13 +134,13 @@ ZSTDLIB_API size_t ZBUFF_decompressContinue(ZBUFF_DCtx* dctx, * *srcSizePtr and *dstCapacityPtr can be any size. * 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. -* 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), * or 0 when a frame is completely decoded, * or an error code, which can be tested using ZBUFF_isError(). * * 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 . * *******************************************************************************/ diff --git a/lib/zbuff_static.h b/lib/zbuff_static.h index 405508900..9fb522e5f 100644 --- a/lib/zbuff_static.h +++ b/lib/zbuff_static.h @@ -51,7 +51,9 @@ extern "C" { /* ************************************* * Advanced Streaming functions ***************************************/ -ZSTDLIB_API size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params); +ZSTDLIB_API size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* cctx, + const void* dict, size_t dictSize, + ZSTD_parameters params, U64 pledgedSrcSize); #if defined (__cplusplus) diff --git a/lib/zdict.c b/lib/zdict.c index a7c8090a8..122ac8cb2 100644 --- a/lib/zdict.c +++ b/lib/zdict.c @@ -284,8 +284,7 @@ static dictItem ZDICT_analyzePos( return solution; } - { - int i; + { int i; U32 searchLength; U32 refinedStart = start; U32 refinedEnd = end; @@ -575,7 +574,6 @@ static void ZDICT_fillNoise(void* buffer, size_t length) { unsigned acc = PRIME1; size_t p=0;; - for (p=0; p> 21); @@ -595,29 +593,40 @@ static void ZDICT_countEStats(EStats_ress_t esr, U32* countLit, U32* offsetcodeCount, U32* matchlengthCount, U32* litlengthCount, const void* src, size_t srcSize) { - const BYTE* bytePtr; - const U32* u32Ptr; - seqStore_t seqStore; + const seqStore_t* seqStorePtr; if (srcSize > ZSTD_BLOCKSIZE_MAX) srcSize = ZSTD_BLOCKSIZE_MAX; /* protection vs large samples */ ZSTD_copyCCtx(esr.zc, esr.ref); ZSTD_compressBlock(esr.zc, esr.workPlace, ZSTD_BLOCKSIZE_MAX, src, srcSize); - seqStore = ZSTD_copySeqStore(esr.zc); + seqStorePtr = ZSTD_getSeqStore(esr.zc); - /* count stats */ - for(bytePtr = seqStore.litStart; bytePtr < seqStore.lit; bytePtr++) - countLit[*bytePtr]++; - for(u32Ptr = seqStore.offsetStart; u32Ptr < seqStore.offset; u32Ptr++) { - BYTE offcode = (BYTE)ZSTD_highbit(*u32Ptr) + 1; - if (*u32Ptr==0) offcode=0; - offsetcodeCount[offcode]++; + /* literals stats */ + { const BYTE* bytePtr; + for(bytePtr = seqStorePtr->litStart; bytePtr < seqStorePtr->lit; bytePtr++) + countLit[*bytePtr]++; } - for(bytePtr = seqStore.matchLengthStart; bytePtr < seqStore.matchLength; bytePtr++) - matchlengthCount[*bytePtr]++; - for(bytePtr = seqStore.litLengthStart; bytePtr < seqStore.litLength; bytePtr++) - litlengthCount[*bytePtr]++; + + /* seqStats */ + { size_t const nbSeq = (size_t)(seqStorePtr->offset - seqStorePtr->offsetStart); + ZSTD_seqToCodes(seqStorePtr, nbSeq); + + { const BYTE* codePtr = seqStorePtr->offCodeStart; + size_t u; + for (u=0; umlCodeStart; + size_t u; + for (u=0; ullCodeStart; + size_t u; + for (u=0; u= 3) { - const U32 nb = 25; + U32 const nb = 25; + U32 const dictContentSize = ZDICT_dictSize(dictList); U32 u; - U32 dictContentSize = ZDICT_dictSize(dictList); DISPLAYLEVEL(3, "\n %u segments found, of total size %u \n", dictList[0].pos, dictContentSize); DISPLAYLEVEL(3, "list %u best segments \n", nb); for (u=1; u<=nb; u++) { @@ -848,8 +875,7 @@ size_t ZDICT_trainFromBuffer_unsafe( } } } /* create dictionary */ - { - U32 dictContentSize = ZDICT_dictSize(dictList); + { U32 dictContentSize = ZDICT_dictSize(dictList); size_t hSize; BYTE* ptr; U32 u; @@ -894,31 +920,32 @@ size_t ZDICT_trainFromBuffer_unsafe( } +/* issue : samplesBuffer need to be followed by a noisy guard band. +* work around : duplicate the buffer, and add the noise */ size_t ZDICT_trainFromBuffer_advanced(void* dictBuffer, size_t dictBufferCapacity, const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, ZDICT_params_t params) { - size_t sBuffSize; void* newBuff; - size_t result; + size_t sBuffSize; { unsigned u; for (u=0, sBuffSize=0; u no dictionary */ newBuff = malloc(sBuffSize + NOISELENGTH); if (!newBuff) return ERROR(memory_allocation); memcpy(newBuff, samplesBuffer, sBuffSize); ZDICT_fillNoise((char*)newBuff + sBuffSize, NOISELENGTH); /* guard band, for end of buffer condition */ - result = ZDICT_trainFromBuffer_unsafe(dictBuffer, dictBufferCapacity, + { size_t const result = ZDICT_trainFromBuffer_unsafe( + dictBuffer, dictBufferCapacity, newBuff, samplesSizes, nbSamples, params); - free(newBuff); - return result; + free(newBuff); + return result; } } -/* issue : samplesBuffer need to be followed by a noisy guard band. -* work around : duplicate the buffer, and add the noise ? */ size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity, const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples) { diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index ddb816b18..1c07a173b 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -80,7 +80,6 @@ static void ZSTD_resetSeqStore(seqStore_t* ssPtr) ssPtr->lit = ssPtr->litStart; ssPtr->litLength = ssPtr->litLengthStart; ssPtr->matchLength = ssPtr->matchLengthStart; - ssPtr->dumps = ssPtr->dumpsStart; } @@ -101,7 +100,6 @@ struct ZSTD_CCtx_s U32 stage; ZSTD_parameters params; void* workSpace; - size_t targetSrcSize; /* optimize compression for this source size */ size_t workSpaceSize; size_t blockSize; size_t hbSize; @@ -130,73 +128,106 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) return 0; /* reserved as a potential error code in the future */ } -seqStore_t ZSTD_copySeqStore(const ZSTD_CCtx* ctx) /* hidden interface */ +const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */ { - return ctx->seqStore; + return &(ctx->seqStore); +} + + +#define CLAMP(val,min,max) { if (valmax) val=max; } +#define CLAMPCHECK(val,min,max) { if ((valmax)) return ERROR(compressionParameter_unsupported); } + +/** ZSTD_checkParams() : + ensure param values remain within authorized range. + @return : 0, or an error code if one value is beyond authorized range */ +size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) +{ + CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); + CLAMPCHECK(cParams.contentLog, ZSTD_CONTENTLOG_MIN, ZSTD_CONTENTLOG_MAX); + CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); + CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); + { U32 const searchLengthMin = (cParams.strategy == ZSTD_btopt) ? ZSTD_SEARCHLENGTH_MIN : ZSTD_SEARCHLENGTH_MIN+1; + U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1; + CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); } + CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); + if ((U32)(cParams.strategy) > (U32)ZSTD_btopt) return ERROR(compressionParameter_unsupported); + return 0; } static unsigned ZSTD_highbit(U32 val); -#define CLAMP(val,min,max) { if (valmax) val=max; } - -/** ZSTD_validateParams() : - correct params value to remain within authorized range, - optimize for `srcSize` if srcSize > 0 */ -void ZSTD_validateParams(ZSTD_parameters* params) +/** ZSTD_checkCParams_advanced() : + temporary work-around, while the compressor compatibility remains limited regarding windowLog < 18 */ +size_t ZSTD_checkCParams_advanced(ZSTD_compressionParameters cParams, U64 srcSize) { - /* validate params */ - if (MEM_32bits()) if (params->windowLog > 25) params->windowLog = 25; /* 32 bits mode cannot flush > 24 bits */ - CLAMP(params->windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); - CLAMP(params->contentLog, ZSTD_CONTENTLOG_MIN, ZSTD_CONTENTLOG_MAX); - CLAMP(params->hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); - CLAMP(params->searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); - { U32 const searchLengthMin = (params->strategy == ZSTD_btopt) ? ZSTD_SEARCHLENGTH_MIN : ZSTD_SEARCHLENGTH_MIN+1; - U32 const searchLengthMax = (params->strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1; - CLAMP(params->searchLength, searchLengthMin, searchLengthMax); } - CLAMP(params->targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); - if ((U32)params->strategy>(U32)ZSTD_btopt) params->strategy = ZSTD_btopt; + if (srcSize > (1ULL << ZSTD_WINDOWLOG_MIN)) return ZSTD_checkCParams(cParams); + if (cParams.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) return ERROR(compressionParameter_unsupported); + if (srcSize <= (1ULL << cParams.windowLog)) cParams.windowLog = ZSTD_WINDOWLOG_MIN; /* fake value - temporary work around */ + if (srcSize <= (1ULL << cParams.contentLog)) cParams.contentLog = ZSTD_CONTENTLOG_MIN; /* fake value - temporary work around */ + if ((srcSize <= (1ULL << cParams.hashLog)) && ((U32)cParams.strategy < (U32)ZSTD_btlazy2)) cParams.hashLog = ZSTD_HASHLOG_MIN; /* fake value - temporary work around */ + return ZSTD_checkCParams(cParams); +} + + +/** ZSTD_adjustParams() : + optimize params for q given input (`srcSize` and `dictSize`). + mostly downsizing to reduce memory consumption and initialization. + Both `srcSize` and `dictSize` are optional (use 0 if unknown), + but if both are 0, no optimization can be done. + Note : params is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */ +void ZSTD_adjustCParams(ZSTD_compressionParameters* params, U64 srcSize, size_t dictSize) +{ + if (srcSize+dictSize == 0) return; /* no size information available : no adjustment */ /* resize params, to use less memory when necessary */ - if ((params->srcSize > 0) && (params->srcSize < (1<srcSize)-1) + 1; - if (params->windowLog > srcLog) params->windowLog = srcLog; - } + { U32 const minSrcSize = (srcSize==0) ? 500 : 0; + U64 const rSize = srcSize + dictSize + minSrcSize; + if (rSize < (1<windowLog > srcLog) params->windowLog = srcLog; + } } if (params->hashLog > params->windowLog) params->hashLog = params->windowLog; - { U32 const btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_btopt); - if (params->contentLog > params->windowLog+btPlus) params->contentLog = params->windowLog+btPlus; } /* <= ZSTD_CONTENTLOG_MAX */ + { U32 const btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_btopt); + U32 const maxContentLog = params->windowLog+btPlus; + if (params->contentLog > maxContentLog) params->contentLog = maxContentLog; } /* <= ZSTD_CONTENTLOG_MAX */ if (params->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) params->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */ + if ((params->hashLog < ZSTD_HASHLOG_MIN) && ((U32)params->strategy >= (U32)ZSTD_btlazy2)) params->hashLog = ZSTD_HASHLOG_MIN; /* required to ensure collision resistance in bt */ } -size_t ZSTD_sizeofCCtx(ZSTD_parameters params) /* hidden interface, for paramagrill */ +size_t ZSTD_sizeofCCtx(ZSTD_compressionParameters cParams) /* hidden interface, for paramagrill */ { ZSTD_CCtx* zc = ZSTD_createCCtx(); - ZSTD_compressBegin_advanced(zc, NULL, 0, params); - { size_t const size = sizeof(*zc) + zc->workSpaceSize; + ZSTD_parameters params; + params.cParams = cParams; + params.fParams.contentSizeFlag = 1; + ZSTD_compressBegin_advanced(zc, NULL, 0, params, 0); + { size_t const ccsize = sizeof(*zc) + zc->workSpaceSize; ZSTD_freeCCtx(zc); - return size; } + return ccsize; } } - +/*! ZSTD_resetCCtx_advanced() : + note : 'params' is expected to be validated */ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, ZSTD_parameters params) { /* note : params considered validated here */ - const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.windowLog); - const U32 divider = (params.searchLength==3) ? 3 : 4; + const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog); + const U32 divider = (params.cParams.searchLength==3) ? 3 : 4; const size_t maxNbSeq = blockSize / divider; - const size_t tokenSpace = blockSize + 8*maxNbSeq; - const size_t contentSize = (params.strategy == ZSTD_fast) ? 0 : (1 << params.contentLog); - const size_t hSize = 1 << params.hashLog; + const size_t tokenSpace = blockSize + 11*maxNbSeq; + const size_t contentSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.contentLog); + const size_t hSize = 1 << params.cParams.hashLog; const size_t h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0; const size_t tableSpace = (contentSize + hSize + h3Size) * sizeof(U32); /* Check if workSpace is large enough, alloc a new one if needed */ - { size_t const optSpace = ((1<workSpaceSize < neededSpace) { free(zc->workSpace); zc->workSpace = malloc(neededSpace); @@ -211,7 +242,7 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, zc->seqStore.buffer = zc->contentTable + contentSize; zc->hufTable = (HUF_CElt*)zc->seqStore.buffer; zc->flagStaticTables = 0; - zc->seqStore.buffer = (U32*)(zc->seqStore.buffer) + 256; + zc->seqStore.buffer = ((U32*)(zc->seqStore.buffer)) + 256; zc->nextToUpdate = 1; zc->nextSrc = NULL; @@ -222,26 +253,27 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, zc->params = params; zc->blockSize = blockSize; - zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer); - zc->seqStore.offCodeStart = (BYTE*) (zc->seqStore.offsetStart + maxNbSeq); - zc->seqStore.litStart = zc->seqStore.offCodeStart + maxNbSeq; - zc->seqStore.litLengthStart = zc->seqStore.litStart + blockSize; - zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + maxNbSeq; - zc->seqStore.dumpsStart = zc->seqStore.matchLengthStart + maxNbSeq; - if (params.strategy == ZSTD_btopt) { - zc->seqStore.litFreq = (U32*)((void*)(zc->seqStore.dumpsStart + maxNbSeq)); + if (params.cParams.strategy == ZSTD_btopt) { + zc->seqStore.litFreq = (U32*)(zc->seqStore.buffer); zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (1<seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (1<seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1); + zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1); zc->seqStore.matchTable = (ZSTD_match_t*)((void*)(zc->seqStore.offCodeFreq + (1<seqStore.priceTable = (ZSTD_optimal_t*)((void*)(zc->seqStore.matchTable + ZSTD_OPT_NUM+1)); + zc->seqStore.buffer = zc->seqStore.priceTable + ZSTD_OPT_NUM+1; zc->seqStore.litLengthSum = 0; } + zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer); + zc->seqStore.litLengthStart = (U16*) (void*)(zc->seqStore.offsetStart + maxNbSeq); + zc->seqStore.matchLengthStart = (U16*) (void*)(zc->seqStore.litLengthStart + maxNbSeq); + zc->seqStore.llCodeStart = (BYTE*) (zc->seqStore.matchLengthStart + maxNbSeq); + zc->seqStore.mlCodeStart = zc->seqStore.llCodeStart + maxNbSeq; + zc->seqStore.offCodeStart = zc->seqStore.mlCodeStart + maxNbSeq; + zc->seqStore.litStart = zc->seqStore.offCodeStart + maxNbSeq; zc->hbSize = 0; zc->stage = 0; zc->loadedDictEnd = 0; - zc->targetSrcSize = 0; return 0; } @@ -259,8 +291,8 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params); /* copy tables */ - { const size_t contentSize = (srcCCtx->params.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.contentLog); - const size_t hSize = 1 << srcCCtx->params.hashLog; + { const size_t contentSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.contentLog); + const size_t hSize = 1 << srcCCtx->params.cParams.hashLog; const size_t h3Size = (srcCCtx->hashLog3) ? 1 << srcCCtx->hashLog3 : 0; const size_t tableSpace = (contentSize + hSize + h3Size) * sizeof(U32); memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace); @@ -279,7 +311,6 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) dstCCtx->dictLimit = srcCCtx->dictLimit; dstCCtx->lowLimit = srcCCtx->lowLimit; dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd; - dstCCtx->targetSrcSize= srcCCtx->targetSrcSize; /* copy entropy tables */ dstCCtx->flagStaticTables = srcCCtx->flagStaticTables; @@ -295,7 +326,7 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) /*! ZSTD_reduceTable() : -* rescale indexes from a table (indexes are U32) */ +* reduce table indexes by `reducerValue` */ static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue) { U32 u; @@ -309,10 +340,10 @@ static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reduce * rescale all indexes to avoid future overflow (indexes are U32) */ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue) { - { const U32 hSize = 1 << zc->params.hashLog; + { const U32 hSize = 1 << zc->params.cParams.hashLog; ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); } - { const U32 contentSize = (zc->params.strategy == ZSTD_fast) ? 0 : (1 << zc->params.contentLog); + { const U32 contentSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.contentLog); ZSTD_reduceTable(zc->contentTable, contentSize, reducerValue); } { const U32 h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0; @@ -573,11 +604,59 @@ static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc, ostart[4] = (BYTE)(cLitSize); break; } - return lhSize+cLitSize; } +void ZSTD_seqToCodes(const seqStore_t* seqStorePtr, size_t const nbSeq) +{ + /* LL codes */ + { static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 16, 17, 17, 18, 18, 19, 19, + 20, 20, 20, 20, 21, 21, 21, 21, + 22, 22, 22, 22, 22, 22, 22, 22, + 23, 23, 23, 23, 23, 23, 23, 23, + 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24 }; + const BYTE LL_deltaCode = 19; + U16* const llTable = seqStorePtr->litLengthStart; + BYTE* const llCodeTable = seqStorePtr->llCodeStart; + size_t u; + for (u=0; ulongLength; llTable[u] = (U16)ll; } + llCodeTable[u] = (ll>63) ? (BYTE)ZSTD_highbit(ll) + LL_deltaCode : LL_Code[ll]; + } } + + /* Offset codes */ + { const U32* const offsetTable = seqStorePtr->offsetStart; + BYTE* const ofCodeTable = seqStorePtr->offCodeStart; + size_t u; + for (u=0; umatchLengthStart; + BYTE* const mlCodeTable = seqStorePtr->mlCodeStart; + size_t u; + for (u=0; ulongLength; mlTable[u] = (U16)ml; } + mlCodeTable[u] = (ml>127) ? (BYTE)ZSTD_highbit(ml) + ML_deltaCode : ML_Code[ml]; + } } +} + + size_t ZSTD_compressSequences(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, size_t srcSize) @@ -589,15 +668,17 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, FSE_CTable* CTable_OffsetBits = zc->offcodeCTable; FSE_CTable* CTable_MatchLength = zc->matchlengthCTable; U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ - const BYTE* const llTable = seqStorePtr->litLengthStart; - const BYTE* const llPtr = seqStorePtr->litLength; - const BYTE* const mlTable = seqStorePtr->matchLengthStart; + U16* const llTable = seqStorePtr->litLengthStart; + U16* const mlTable = seqStorePtr->matchLengthStart; const U32* const offsetTable = seqStorePtr->offsetStart; - BYTE* const offCodeTable = seqStorePtr->offCodeStart; + const U32* const offsetTableEnd = seqStorePtr->offset; + BYTE* const ofCodeTable = seqStorePtr->offCodeStart; + BYTE* const llCodeTable = seqStorePtr->llCodeStart; + BYTE* const mlCodeTable = seqStorePtr->mlCodeStart; BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstCapacity; BYTE* op = ostart; - size_t const nbSeq = llPtr - llTable; + size_t const nbSeq = offsetTableEnd - offsetTable; BYTE* seqHead; /* Compress literals */ @@ -609,111 +690,94 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, } /* Sequences Header */ - if ((oend-op) < MIN_SEQUENCES_SIZE) return ERROR(dstSize_tooSmall); + if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall); if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq; else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2; else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; if (nbSeq==0) goto _check_compressibility; - /* dumps : contains rests of large lengths */ - if ((oend-op) < 3 /* dumps */ + 1 /*seqHead*/) - return ERROR(dstSize_tooSmall); - seqHead = op; - { size_t const dumpsLength = seqStorePtr->dumps - seqStorePtr->dumpsStart; - if (dumpsLength < 512) { - op[0] = (BYTE)(dumpsLength >> 8); - op[1] = (BYTE)(dumpsLength); - op += 2; - } else { - op[0] = 2; - op[1] = (BYTE)(dumpsLength>>8); - op[2] = (BYTE)(dumpsLength); - op += 3; - } - if ((size_t)(oend-op) < dumpsLength+6) return ERROR(dstSize_tooSmall); - memcpy(op, seqStorePtr->dumpsStart, dumpsLength); - op += dumpsLength; - } + /* seqHead : flags for FSE encoding type */ + seqHead = op++; #define MIN_SEQ_FOR_DYNAMIC_FSE 64 #define MAX_SEQ_FOR_STATIC_FSE 1000 + /* convert length/distances into codes */ + ZSTD_seqToCodes(seqStorePtr, nbSeq); + /* CTable for Literal Lengths */ - { U32 max = MaxLL; - size_t const mostFrequent = FSE_countFast(count, &max, llTable, nbSeq); - if ((mostFrequent == nbSeq) && (nbSeq > 2)) { - *op++ = llTable[0]; - FSE_buildCTable_rle(CTable_LitLength, (BYTE)max); - LLtype = FSE_ENCODING_RLE; - } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { - LLtype = FSE_ENCODING_STATIC; - } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LLbits-1)))) { - FSE_buildCTable_raw(CTable_LitLength, LLbits); - LLtype = FSE_ENCODING_RAW; - } else { - size_t NCountSize; - size_t nbSeq_1 = nbSeq; - const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max); - if (count[llTable[nbSeq-1]]>1) { count[llTable[nbSeq-1]]--; nbSeq_1--; } - FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max); - NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */ - if (FSE_isError(NCountSize)) return ERROR(GENERIC); - op += NCountSize; - FSE_buildCTable(CTable_LitLength, norm, max, tableLog); - LLtype = FSE_ENCODING_DYNAMIC; - }} + { U32 max = MaxLL; + size_t const mostFrequent = FSE_countFast(count, &max, llCodeTable, nbSeq); + if ((mostFrequent == nbSeq) && (nbSeq > 2)) { + *op++ = llCodeTable[0]; + FSE_buildCTable_rle(CTable_LitLength, (BYTE)max); + LLtype = FSE_ENCODING_RLE; + } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { + LLtype = FSE_ENCODING_STATIC; + } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) { + FSE_buildCTable(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog); + LLtype = FSE_ENCODING_RAW; + } else { + size_t nbSeq_1 = nbSeq; + const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max); + if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; } + FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max); + { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */ + if (FSE_isError(NCountSize)) return ERROR(GENERIC); + op += NCountSize; } + FSE_buildCTable(CTable_LitLength, norm, max, tableLog); + LLtype = FSE_ENCODING_DYNAMIC; + } } - /* Offset codes */ - { size_t i; for (i=0; i 2)) { - *op++ = offCodeTable[0]; - FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max); - Offtype = FSE_ENCODING_RLE; - } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { - Offtype = FSE_ENCODING_STATIC; - } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (Offbits-1)))) { - FSE_buildCTable_raw(CTable_OffsetBits, Offbits); - Offtype = FSE_ENCODING_RAW; - } else { - size_t NCountSize; - size_t nbSeq_1 = nbSeq; - const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max); - if (count[offCodeTable[nbSeq-1]]>1) { count[offCodeTable[nbSeq-1]]--; nbSeq_1--; } - FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max); - NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */ - if (FSE_isError(NCountSize)) return ERROR(GENERIC); - op += NCountSize; - FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog); - Offtype = FSE_ENCODING_DYNAMIC; - }} + /* CTable for Offsets */ + { U32 max = MaxOff; + size_t const mostFrequent = FSE_countFast(count, &max, ofCodeTable, nbSeq); + if ((mostFrequent == nbSeq) && (nbSeq > 2)) { + *op++ = ofCodeTable[0]; + FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max); + Offtype = FSE_ENCODING_RLE; + } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { + Offtype = FSE_ENCODING_STATIC; + } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (Offbits-1)))) { + FSE_buildCTable_raw(CTable_OffsetBits, Offbits); + Offtype = FSE_ENCODING_RAW; + } else { + size_t nbSeq_1 = nbSeq; + const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max); + if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; } + FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max); + { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */ + if (FSE_isError(NCountSize)) return ERROR(GENERIC); + op += NCountSize; } + FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog); + Offtype = FSE_ENCODING_DYNAMIC; + } } /* CTable for MatchLengths */ - { U32 max = MaxML; - size_t const mostFrequent = FSE_countFast(count, &max, mlTable, nbSeq); - if ((mostFrequent == nbSeq) && (nbSeq > 2)) { - *op++ = *mlTable; - FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max); - MLtype = FSE_ENCODING_RLE; - } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { - MLtype = FSE_ENCODING_STATIC; - } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (MLbits-1)))) { - FSE_buildCTable_raw(CTable_MatchLength, MLbits); - MLtype = FSE_ENCODING_RAW; - } else { - size_t NCountSize; - const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max); - FSE_normalizeCount(norm, tableLog, count, nbSeq, max); - NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */ - if (FSE_isError(NCountSize)) return ERROR(GENERIC); - op += NCountSize; - FSE_buildCTable(CTable_MatchLength, norm, max, tableLog); - MLtype = FSE_ENCODING_DYNAMIC; - }} + { U32 max = MaxML; + size_t const mostFrequent = FSE_countFast(count, &max, mlCodeTable, nbSeq); + if ((mostFrequent == nbSeq) && (nbSeq > 2)) { + *op++ = *mlCodeTable; + FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max); + MLtype = FSE_ENCODING_RLE; + } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { + MLtype = FSE_ENCODING_STATIC; + } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) { + FSE_buildCTable(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog); + MLtype = FSE_ENCODING_RAW; + } else { + size_t nbSeq_1 = nbSeq; + const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max); + if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; } + FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max); + { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */ + if (FSE_isError(NCountSize)) return ERROR(GENERIC); + op += NCountSize; } + FSE_buildCTable(CTable_MatchLength, norm, max, tableLog); + MLtype = FSE_ENCODING_DYNAMIC; + } } - seqHead[0] += (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); + *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); zc->flagStaticTables = 0; /* Encoding Sequences */ @@ -723,45 +787,56 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, FSE_CState_t stateLitLength; { size_t const errorCode = BIT_initCStream(&blockStream, op, oend-op); - if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); } /* not enough space remaining */ + if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); } /* not enough space remaining */ /* first symbols */ - FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlTable[nbSeq-1]); - FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, offCodeTable[nbSeq-1]); - FSE_initCState2(&stateLitLength, CTable_LitLength, llTable[nbSeq-1]); - BIT_addBits(&blockStream, offsetTable[nbSeq-1], offCodeTable[nbSeq-1] ? (offCodeTable[nbSeq-1]-1) : 0); + FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]); + FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]); + FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]); + BIT_addBits(&blockStream, llTable[nbSeq-1], LL_bits[llCodeTable[nbSeq-1]]); + if (MEM_32bits()) BIT_flushBits(&blockStream); + BIT_addBits(&blockStream, mlTable[nbSeq-1], ML_bits[mlCodeTable[nbSeq-1]]); + if (MEM_32bits()) BIT_flushBits(&blockStream); + BIT_addBits(&blockStream, offsetTable[nbSeq-1], ofCodeTable[nbSeq-1]); BIT_flushBits(&blockStream); - { int i; for (i=(int)nbSeq-2; i>=0; i--) { - const BYTE mlCode = mlTable[i]; - const U32 offset = offsetTable[i]; - const BYTE offCode = offCodeTable[i]; /* 32b*/ /* 64b*/ - const U32 nbBits = (offCode-1) + (!offCode); - const BYTE litLength = llTable[i]; /* (7)*/ /* (7)*/ - FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 17 */ /* 17 */ - if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */ - FSE_encodeSymbol(&blockStream, &stateLitLength, litLength); /* 17 */ /* 27 */ - FSE_encodeSymbol(&blockStream, &stateOffsetBits, offCode); /* 26 */ /* 36 */ - if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */ - BIT_addBits(&blockStream, offset, nbBits); /* 31 */ /* 62 */ /* 24 bits max in 32-bits mode */ - BIT_flushBits(&blockStream); /* 7 */ /* 7 */ - }} + { size_t n; + for (n=nbSeq-2 ; n 64-7-(LLFSELog+MLFSELog+OffFSELog))) + BIT_flushBits(&blockStream); /* (7)*/ + BIT_addBits(&blockStream, llTable[n], llBits); + if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream); + BIT_addBits(&blockStream, mlTable[n], mlBits); + if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/ + BIT_addBits(&blockStream, offsetTable[n], ofBits); /* 31 */ + BIT_flushBits(&blockStream); /* (7)*/ + } } FSE_flushCState(&blockStream, &stateMatchLength); FSE_flushCState(&blockStream, &stateOffsetBits); FSE_flushCState(&blockStream, &stateLitLength); - { size_t const streamSize = BIT_closeCStream(&blockStream); - if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */ - op += streamSize; } - } + { size_t const streamSize = BIT_closeCStream(&blockStream); + if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */ + op += streamSize; + } } /* check compressibility */ _check_compressibility: - { size_t const minGain = ZSTD_minGain(srcSize); - size_t const maxCSize = srcSize - minGain; - if ((size_t)(op-ostart) >= maxCSize) return 0; - } + { size_t const minGain = ZSTD_minGain(srcSize); + size_t const maxCSize = srcSize - minGain; + if ((size_t)(op-ostart) >= maxCSize) return 0; } return op - ostart; } @@ -776,10 +851,11 @@ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const B { #if 0 /* for debug */ static const BYTE* g_start = NULL; + const U32 pos = (U32)(literals - g_start); if (g_start==NULL) g_start = literals; - //if (literals - g_start == 8695) - printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n", - (U32)(literals - g_start), (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode); + if ((pos > 200000000) && (pos < 200900000)) + printf("Cpos %6u :%5u literals & match %3u bytes at distance %6u \n", + pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode); #endif ZSTD_statsUpdatePrices(&seqStorePtr->stats, litLength, literals, offsetCode, matchCode); @@ -788,39 +864,15 @@ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const B seqStorePtr->lit += litLength; /* literal Length */ - if (litLength >= MaxLL) { - *(seqStorePtr->litLength++) = MaxLL; - if (litLength<255 + MaxLL) { - *(seqStorePtr->dumps++) = (BYTE)(litLength - MaxLL); - } else { - *(seqStorePtr->dumps++) = 255; - if (litLength < (1<<15)) { - MEM_writeLE16(seqStorePtr->dumps, (U16)(litLength<<1)); - seqStorePtr->dumps += 2; - } else { - MEM_writeLE32(seqStorePtr->dumps, (U32)((litLength<<1)+1)); - seqStorePtr->dumps += 3; - } } } - else *(seqStorePtr->litLength++) = (BYTE)litLength; + if (litLength>=65535) { *(seqStorePtr->litLength++) = 65535; seqStorePtr->longLength = (U32)litLength; } + else *seqStorePtr->litLength++ = (U16)litLength; /* match offset */ - *(seqStorePtr->offset++) = (U32)offsetCode; + *(seqStorePtr->offset++) = (U32)offsetCode + 1; /* match Length */ - if (matchCode >= MaxML) { - *(seqStorePtr->matchLength++) = MaxML; - if (matchCode < 255+MaxML) { - *(seqStorePtr->dumps++) = (BYTE)(matchCode - MaxML); - } else { - *(seqStorePtr->dumps++) = 255; - if (matchCode < (1<<15)) { - MEM_writeLE16(seqStorePtr->dumps, (U16)(matchCode<<1)); - seqStorePtr->dumps += 2; - } else { - MEM_writeLE32(seqStorePtr->dumps, (U32)((matchCode<<1)+1)); - seqStorePtr->dumps += 3; - } } } - else *(seqStorePtr->matchLength++) = (BYTE)matchCode; + if (matchCode>=65535) { *(seqStorePtr->matchLength++) = 65535; seqStorePtr->longLength = (U32)matchCode; } + else *seqStorePtr->matchLength++ = (U16)matchCode; } @@ -960,7 +1012,7 @@ static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls) { U32* const hashTable = zc->hashTable; - const U32 hBits = zc->params.hashLog; + const U32 hBits = zc->params.cParams.hashLog; const BYTE* const base = zc->base; const BYTE* ip = base + zc->nextToUpdate; const BYTE* const iend = ((const BYTE*)end) - 8; @@ -979,7 +1031,7 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, const U32 mls) { U32* const hashTable = zc->hashTable; - const U32 hBits = zc->params.hashLog; + const U32 hBits = zc->params.cParams.hashLog; seqStore_t* seqStorePtr = &(zc->seqStore); const BYTE* const base = zc->base; const BYTE* const istart = (const BYTE*)src; @@ -1055,7 +1107,7 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - const U32 mls = ctx->params.searchLength; + const U32 mls = ctx->params.cParams.searchLength; switch(mls) { default: @@ -1076,7 +1128,7 @@ static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, const U32 mls) { U32* hashTable = ctx->hashTable; - const U32 hBits = ctx->params.hashLog; + const U32 hBits = ctx->params.cParams.hashLog; seqStore_t* seqStorePtr = &(ctx->seqStore); const BYTE* const base = ctx->base; const BYTE* const dictBase = ctx->dictBase; @@ -1146,8 +1198,8 @@ static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base); /* check immediate repcode */ while (ip <= ilimit) { - U32 current2 = (U32)(ip-base); - const U32 repIndex2 = current2 - offset_2; + U32 const current2 = (U32)(ip-base); + U32 const repIndex2 = current2 - offset_2; const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2; if ( ((repIndex2 <= dictLimit-4) || (repIndex2 >= dictLimit)) && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { @@ -1174,7 +1226,7 @@ static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - const U32 mls = ctx->params.searchLength; + const U32 mls = ctx->params.cParams.searchLength; switch(mls) { default: @@ -1200,10 +1252,10 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co U32 extDict) { U32* const hashTable = zc->hashTable; - const U32 hashLog = zc->params.hashLog; + const U32 hashLog = zc->params.cParams.hashLog; const size_t h = ZSTD_hashPtr(ip, hashLog, mls); U32* const bt = zc->contentTable; - const U32 btLog = zc->params.contentLog - 1; + const U32 btLog = zc->params.cParams.contentLog - 1; const U32 btMask= (1 << btLog) - 1; U32 matchIndex = hashTable[h]; size_t commonLengthSmaller=0, commonLengthLarger=0; @@ -1302,10 +1354,10 @@ static size_t ZSTD_insertBtAndFindBestMatch ( U32 extDict) { U32* const hashTable = zc->hashTable; - const U32 hashLog = zc->params.hashLog; + const U32 hashLog = zc->params.cParams.hashLog; const size_t h = ZSTD_hashPtr(ip, hashLog, mls); U32* const bt = zc->contentTable; - const U32 btLog = zc->params.contentLog - 1; + const U32 btLog = zc->params.cParams.contentLog - 1; const U32 btMask= (1 << btLog) - 1; U32 matchIndex = hashTable[h]; size_t commonLengthSmaller=0, commonLengthLarger=0; @@ -1464,9 +1516,9 @@ FORCE_INLINE U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls) { U32* const hashTable = zc->hashTable; - const U32 hashLog = zc->params.hashLog; + const U32 hashLog = zc->params.cParams.hashLog; U32* const chainTable = zc->contentTable; - const U32 chainMask = (1 << zc->params.contentLog) - 1; + const U32 chainMask = (1 << zc->params.cParams.contentLog) - 1; const BYTE* const base = zc->base; const U32 target = (U32)(ip - base); U32 idx = zc->nextToUpdate; @@ -1491,7 +1543,7 @@ size_t ZSTD_HcFindBestMatch_generic ( const U32 maxNbAttempts, const U32 mls, const U32 extDict) { U32* const chainTable = zc->contentTable; - const U32 chainSize = (1 << zc->params.contentLog); + const U32 chainSize = (1 << zc->params.cParams.contentLog); const U32 chainMask = chainSize-1; const BYTE* const base = zc->base; const BYTE* const dictBase = zc->dictBase; @@ -1581,8 +1633,8 @@ void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, const BYTE* const base = ctx->base + ctx->dictLimit; size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE; - const U32 maxSearches = 1 << ctx->params.searchLog; - const U32 mls = ctx->params.searchLength; + const U32 maxSearches = 1 << ctx->params.cParams.searchLog; + const U32 mls = ctx->params.cParams.searchLength; typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr, @@ -1741,8 +1793,8 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, const BYTE* const dictStart = dictBase + ctx->lowLimit; size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE; - const U32 maxSearches = 1 << ctx->params.searchLog; - const U32 mls = ctx->params.searchLength; + const U32 maxSearches = 1 << ctx->params.cParams.searchLog; + const U32 mls = ctx->params.cParams.searchLength; typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr, @@ -1931,7 +1983,7 @@ static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int 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.cParams.strategy, zc->lowLimit < zc->dictLimit); if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */ blockCompressor(zc, src, srcSize); return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize); @@ -1949,7 +2001,7 @@ static size_t ZSTD_compress_generic (ZSTD_CCtx* zc, const BYTE* ip = (const BYTE*)src; BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; - const U32 maxDist = 1 << zc->params.windowLog; + const U32 maxDist = 1 << zc->params.cParams.windowLog; ZSTD_stats_t* stats = &zc->seqStore.stats; ZSTD_statsInit(stats); @@ -1988,13 +2040,13 @@ static size_t ZSTD_compress_generic (ZSTD_CCtx* zc, op += cSize; } - ZSTD_statsPrint(stats, zc->params.searchLength); + ZSTD_statsPrint(stats, zc->params.cParams.searchLength); return op-ostart; } static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc, - void* dst, size_t dstSize, + void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 frame) { @@ -2003,10 +2055,10 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc, if (frame && (zc->stage==0)) { hbSize = zc->hbSize; - if (dstSize <= hbSize) return ERROR(dstSize_tooSmall); + if (dstCapacity <= hbSize) return ERROR(dstSize_tooSmall); zc->stage = 1; memcpy(dst, zc->headerBuffer, hbSize); - dstSize -= hbSize; + dstCapacity -= hbSize; dst = (char*)dst + hbSize; } @@ -2024,8 +2076,8 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc, /* preemptive overflow correction */ if (zc->lowLimit > (1<<30)) { - U32 const btplus = (zc->params.strategy == ZSTD_btlazy2) || (zc->params.strategy == ZSTD_btopt); - U32 const contentMask = (1 << (zc->params.contentLog - btplus)) - 1; + U32 const btplus = (zc->params.cParams.strategy == ZSTD_btlazy2) || (zc->params.cParams.strategy == ZSTD_btopt); + U32 const contentMask = (1 << (zc->params.cParams.contentLog - btplus)) - 1; U32 const newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */ U32 const correction = zc->lowLimit - newLowLimit; ZSTD_reduceIndex(zc, correction); @@ -2045,8 +2097,8 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc, zc->nextSrc = ip + srcSize; { size_t const cSize = frame ? - ZSTD_compress_generic (zc, dst, dstSize, src, srcSize) : - ZSTD_compressBlock_internal (zc, dst, dstSize, src, srcSize); + ZSTD_compress_generic (zc, dst, dstCapacity, src, srcSize) : + ZSTD_compressBlock_internal (zc, dst, dstCapacity, src, srcSize); if (ZSTD_isError(cSize)) return cSize; return cSize + hbSize; } @@ -2054,17 +2106,17 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc, size_t ZSTD_compressContinue (ZSTD_CCtx* zc, - void* dst, size_t dstSize, + void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - return ZSTD_compressContinue_internal(zc, dst, dstSize, src, srcSize, 1); + return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 1); } size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { if (srcSize > ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); - zc->params.searchLength = MINMATCH; /* force ZSTD_btopt to MINMATCH in block mode */ + zc->params.cParams.searchLength = MINMATCH; /* force ZSTD_btopt to MINMATCH in block mode */ ZSTD_LOG_BLOCK("%p: ZSTD_compressBlock searchLength=%d\n", zc->base, zc->params.searchLength); return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 0); } @@ -2086,21 +2138,21 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t zc->nextSrc = iend; if (srcSize <= 8) return 0; - switch(zc->params.strategy) + switch(zc->params.cParams.strategy) { case ZSTD_fast: - ZSTD_fillHashTable (zc, iend, zc->params.searchLength); + ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength); break; case ZSTD_greedy: case ZSTD_lazy: case ZSTD_lazy2: - ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.searchLength); + ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.cParams.searchLength); break; case ZSTD_btlazy2: case ZSTD_btopt: - ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength); + ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength); break; default: @@ -2168,44 +2220,40 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, si if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize); /* 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); + { 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); } } -extern int g_additionalParam; - -/*! ZSTD_compressBegin_advanced() : +/*! ZSTD_compressBegin_internal() : * @return : 0, or an error code */ -size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc, +static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* zc, const void* dict, size_t dictSize, - ZSTD_parameters params) + ZSTD_parameters params, U64 pledgedSrcSize) { -// printf("windowLog=%d hashLog=%d targetSrcSize=%d\n", params.windowLog, params.hashLog, zc->targetSrcSize); - ZSTD_validateParams(¶ms); - U32 hashLog3 = (!zc->targetSrcSize || zc->targetSrcSize >= 8192) ? ZSTD_HASHLOG3_MAX : ((zc->targetSrcSize >= 2048) ? ZSTD_HASHLOG3_MIN + 1 : ZSTD_HASHLOG3_MIN); - zc->hashLog3 = (params.searchLength==3) ? hashLog3 : 0; + U32 hashLog3 = (pledgedSrcSize || pledgedSrcSize >= 8192) ? ZSTD_HASHLOG3_MAX : ((pledgedSrcSize >= 2048) ? ZSTD_HASHLOG3_MIN + 1 : ZSTD_HASHLOG3_MIN); + zc->hashLog3 = (params.cParams.searchLength==3) ? hashLog3 : 0; // printf("windowLog=%d hashLog=%d hashLog3=%d \n", params.windowLog, params.hashLog, zc->hashLog3); { 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 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 */ + U32 const fcsId = (pledgedSrcSize>0) + (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256); /* 0-3 */ + BYTE fdescriptor = (BYTE)(params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN); /* windowLog : 4 KB - 128 MB */ + fdescriptor |= (BYTE)((params.cParams.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; + case 1 : op[5] = (BYTE)(pledgedSrcSize); break; + case 2 : MEM_writeLE16(op+5, (U16)(pledgedSrcSize-256)); break; + case 3 : MEM_writeLE64(op+5, (U64)(pledgedSrcSize)); break; } zc->hbSize = ZSTD_frameHeaderSize_min + ZSTD_fcs_fieldSize[fcsId]; } @@ -2215,27 +2263,46 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc, } -size_t ZSTD_compressBegin_targetSrcSize(ZSTD_CCtx* zc, const void* dict, size_t dictSize, size_t targetSrcSize, int compressionLevel) +/*! ZSTD_compressBegin_advanced() : +* @return : 0, or an error code */ +size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc, + const void* dict, size_t dictSize, + ZSTD_parameters params, U64 pledgedSrcSize) { - zc->targetSrcSize = dictSize ? dictSize : targetSrcSize; - ZSTD_parameters params = ZSTD_getParams(compressionLevel, zc->targetSrcSize); - params.srcSize = 0; - ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_targetSrcSize compressionLevel=%d\n", zc->base, compressionLevel); - return ZSTD_compressBegin_advanced(zc, dict, dictSize, params); + /* compression parameters verification and optimization */ + { size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize); + if (ZSTD_isError(errorCode)) return errorCode; } + + return ZSTD_compressBegin_internal(zc, dict, dictSize, params, pledgedSrcSize); } + 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_parameters params; + params.cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); + params.fParams.contentSizeFlag = 0; + ZSTD_adjustCParams(¶ms.cParams, 0, dictSize); ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_usingDict compressionLevel=%d\n", zc->base, compressionLevel); - return ZSTD_compressBegin_advanced(zc, dict, dictSize, params); + return ZSTD_compressBegin_internal(zc, dict, dictSize, params, 0); } + +size_t ZSTD_compressBegin_targetSrcSize(ZSTD_CCtx* zc, const void* dict, size_t dictSize, size_t targetSrcSize, int compressionLevel) +{ + ZSTD_parameters params; + params.cParams = ZSTD_getCParams(compressionLevel, targetSrcSize, dictSize); + params.fParams.contentSizeFlag = 1; + ZSTD_adjustCParams(¶ms.cParams, targetSrcSize, dictSize); + ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_targetSrcSize compressionLevel=%d\n", zc->base, compressionLevel); + return ZSTD_compressBegin_internal(zc, dict, dictSize, params, targetSrcSize); +} + + size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel) { ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin compressionLevel=%d\n", zc->base, compressionLevel); - return ZSTD_compressBegin_advanced(zc, NULL, 0, ZSTD_getParams(compressionLevel, 0)); + return ZSTD_compressBegin_usingDict(zc, NULL, 0, compressionLevel); } @@ -2283,7 +2350,7 @@ size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* prepare } -size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, +static size_t ZSTD_compress_internal (ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict,size_t dictSize, @@ -2293,35 +2360,48 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, BYTE* op = ostart; /* Init */ - { size_t const errorCode = ZSTD_compressBegin_advanced(ctx, dict, dictSize, params); - if(ZSTD_isError(errorCode)) return errorCode; } + { size_t const errorCode = ZSTD_compressBegin_internal(ctx, dict, dictSize, params, srcSize); + if(ZSTD_isError(errorCode)) return errorCode; } /* body (compression) */ { size_t const oSize = ZSTD_compressContinue (ctx, op, dstCapacity, src, srcSize); - if(ZSTD_isError(oSize)) return oSize; - op += oSize; - dstCapacity -= oSize; } + if(ZSTD_isError(oSize)) return oSize; + op += oSize; + dstCapacity -= oSize; } /* Close frame */ { size_t const oSize = ZSTD_compressEnd(ctx, op, dstCapacity); - if(ZSTD_isError(oSize)) return oSize; - op += oSize; } + if(ZSTD_isError(oSize)) return oSize; + op += oSize; } return (op - ostart); } +size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + ZSTD_parameters params) +{ + size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, srcSize); + if (ZSTD_isError(errorCode)) return errorCode; + return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params); +} + size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize, int compressionLevel) { + ZSTD_parameters params; ZSTD_LOG_BLOCK("%p: ZSTD_compress_usingDict srcSize=%d dictSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, (int)dictSize, compressionLevel); - ctx->targetSrcSize = srcSize; - return ZSTD_compress_advanced(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize)); + params.cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize); + params.fParams.contentSizeFlag = 1; + ZSTD_adjustCParams(¶ms.cParams, srcSize, dictSize); + return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params); } 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); - ctx->targetSrcSize = srcSize; - return ZSTD_compress_advanced(ctx, dst, dstCapacity, src, srcSize, NULL, 0, ZSTD_getParams(compressionLevel, srcSize)); + return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel); } size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel) @@ -2340,124 +2420,125 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcS #define ZSTD_MAX_CLEVEL 22 unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } - -static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { +static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { { /* "default" */ - /* l, W, C, H, S, L, SL, strat */ - { 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */ - { 0, 19, 13, 14, 1, 7, 4, ZSTD_fast }, /* level 1 */ - { 0, 19, 15, 16, 1, 6, 4, ZSTD_fast }, /* level 2 */ - { 0, 20, 18, 20, 1, 6, 4, ZSTD_fast }, /* level 3 */ - { 0, 20, 13, 17, 2, 5, 4, ZSTD_greedy }, /* level 4.*/ - { 0, 20, 15, 18, 3, 5, 4, ZSTD_greedy }, /* level 5 */ - { 0, 21, 16, 19, 2, 5, 4, ZSTD_lazy }, /* level 6 */ - { 0, 21, 17, 20, 3, 5, 4, ZSTD_lazy }, /* level 7 */ - { 0, 21, 18, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 8.*/ - { 0, 21, 20, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 9 */ - { 0, 21, 19, 21, 4, 5, 4, ZSTD_lazy2 }, /* level 10 */ - { 0, 22, 20, 22, 4, 5, 4, ZSTD_lazy2 }, /* level 11 */ - { 0, 22, 20, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 12 */ - { 0, 22, 21, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 13 */ - { 0, 22, 21, 22, 6, 5, 4, ZSTD_lazy2 }, /* level 14 */ - { 0, 22, 21, 21, 5, 5, 4, ZSTD_btlazy2 }, /* level 15 */ - { 0, 23, 22, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 16 */ - { 0, 23, 22, 22, 6, 5, 22, ZSTD_btopt }, /* level 17 */ - { 0, 22, 22, 22, 5, 3, 44, ZSTD_btopt }, /* level 18 */ - { 0, 23, 24, 22, 7, 3, 44, ZSTD_btopt }, /* level 19 */ - { 0, 25, 26, 22, 7, 3, 71, ZSTD_btopt }, /* level 20 */ - { 0, 26, 26, 24, 7, 3,256, ZSTD_btopt }, /* level 21 */ - { 0, 27, 28, 26, 9, 3,256, ZSTD_btopt }, /* level 22 */ + /* W, C, H, S, L, SL, strat */ + { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */ + { 19, 13, 14, 1, 7, 4, ZSTD_fast }, /* level 1 */ + { 19, 15, 16, 1, 6, 4, ZSTD_fast }, /* level 2 */ + { 20, 18, 20, 1, 6, 4, ZSTD_fast }, /* level 3 */ + { 20, 13, 17, 2, 5, 4, ZSTD_greedy }, /* level 4.*/ + { 20, 15, 18, 3, 5, 4, ZSTD_greedy }, /* level 5 */ + { 21, 16, 19, 2, 5, 4, ZSTD_lazy }, /* level 6 */ + { 21, 17, 20, 3, 5, 4, ZSTD_lazy }, /* level 7 */ + { 21, 18, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 8.*/ + { 21, 20, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 9 */ + { 21, 19, 21, 4, 5, 4, ZSTD_lazy2 }, /* level 10 */ + { 22, 20, 22, 4, 5, 4, ZSTD_lazy2 }, /* level 11 */ + { 22, 20, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 12 */ + { 22, 21, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 13 */ + { 22, 21, 22, 6, 5, 4, ZSTD_lazy2 }, /* level 14 */ + { 22, 21, 21, 5, 5, 4, ZSTD_btlazy2 }, /* level 15 */ + { 23, 22, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 16 */ + { 23, 22, 22, 6, 5, 22, ZSTD_btopt }, /* level 17 */ + { 22, 22, 22, 5, 3, 44, ZSTD_btopt }, /* level 18 */ + { 23, 24, 22, 7, 3, 44, ZSTD_btopt }, /* level 19 */ + { 25, 26, 22, 7, 3, 71, ZSTD_btopt }, /* level 20 */ + { 26, 26, 24, 7, 3,256, ZSTD_btopt }, /* level 21 */ + { 27, 28, 26, 9, 3,256, ZSTD_btopt }, /* level 22 */ }, { /* for srcSize <= 256 KB */ - /* l, W, C, H, S, L, T, strat */ - { 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 */ - { 0, 18, 14, 15, 1, 6, 4, ZSTD_fast }, /* level 1 */ - { 0, 18, 14, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */ - { 0, 18, 14, 17, 1, 5, 4, ZSTD_fast }, /* level 3.*/ - { 0, 18, 14, 15, 4, 4, 4, ZSTD_greedy }, /* level 4 */ - { 0, 18, 16, 17, 4, 4, 4, ZSTD_greedy }, /* level 5 */ - { 0, 18, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ - { 0, 18, 17, 17, 4, 4, 4, ZSTD_lazy }, /* level 7 */ - { 0, 18, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */ - { 0, 18, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */ - { 0, 18, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */ - { 0, 18, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */ - { 0, 18, 18, 17, 4, 4, 4, ZSTD_btlazy2 }, /* level 12 */ - { 0, 18, 19, 17, 7, 4, 4, ZSTD_btlazy2 }, /* level 13.*/ - { 0, 18, 17, 19, 8, 4, 24, ZSTD_btopt }, /* level 14.*/ - { 0, 18, 19, 19, 8, 4, 48, ZSTD_btopt }, /* level 15.*/ - { 0, 18, 19, 18, 9, 4,128, ZSTD_btopt }, /* level 16.*/ - { 0, 18, 19, 18, 9, 4,192, ZSTD_btopt }, /* level 17.*/ - { 0, 18, 19, 18, 9, 4,256, ZSTD_btopt }, /* level 18.*/ - { 0, 18, 19, 18, 10, 4,256, ZSTD_btopt }, /* level 19.*/ - { 0, 18, 19, 18, 11, 4,256, ZSTD_btopt }, /* level 20.*/ - { 0, 18, 19, 18, 12, 4,256, ZSTD_btopt }, /* level 21.*/ - { 0, 18, 19, 18, 12, 4,256, ZSTD_btopt }, /* level 22*/ + /* W, C, H, S, L, T, strat */ + { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 */ + { 18, 14, 15, 1, 6, 4, ZSTD_fast }, /* level 1 */ + { 18, 14, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */ + { 18, 14, 17, 1, 5, 4, ZSTD_fast }, /* level 3.*/ + { 18, 14, 15, 4, 4, 4, ZSTD_greedy }, /* level 4 */ + { 18, 16, 17, 4, 4, 4, ZSTD_greedy }, /* level 5 */ + { 18, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ + { 18, 17, 17, 4, 4, 4, ZSTD_lazy }, /* level 7 */ + { 18, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */ + { 18, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */ + { 18, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */ + { 18, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */ + { 18, 18, 17, 4, 4, 4, ZSTD_btlazy2 }, /* level 12 */ + { 18, 19, 17, 7, 4, 4, ZSTD_btlazy2 }, /* level 13.*/ + { 18, 17, 19, 8, 4, 24, ZSTD_btopt }, /* level 14.*/ + { 18, 19, 19, 8, 4, 48, ZSTD_btopt }, /* level 15.*/ + { 18, 19, 18, 9, 4,128, ZSTD_btopt }, /* level 16.*/ + { 18, 19, 18, 9, 4,192, ZSTD_btopt }, /* level 17.*/ + { 18, 19, 18, 9, 4,256, ZSTD_btopt }, /* level 18.*/ + { 18, 19, 18, 10, 4,256, ZSTD_btopt }, /* level 19.*/ + { 18, 19, 18, 11, 4,256, ZSTD_btopt }, /* level 20.*/ + { 18, 19, 18, 12, 4,256, ZSTD_btopt }, /* level 21.*/ + { 18, 19, 18, 12, 4,256, ZSTD_btopt }, /* level 22*/ }, { /* for srcSize <= 128 KB */ - /* l, W, C, H, S, L, T, strat */ - { 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */ - { 0, 17, 12, 13, 1, 6, 4, ZSTD_fast }, /* level 1 */ - { 0, 17, 13, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */ - { 0, 17, 13, 14, 2, 5, 4, ZSTD_greedy }, /* level 3 */ - { 0, 17, 13, 15, 3, 4, 4, ZSTD_greedy }, /* level 4 */ - { 0, 17, 15, 17, 4, 4, 4, ZSTD_greedy }, /* level 5 */ - { 0, 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ - { 0, 17, 15, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 7 */ - { 0, 17, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */ - { 0, 17, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */ - { 0, 17, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */ - { 0, 17, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */ - { 0, 17, 17, 17, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */ - { 0, 17, 18, 17, 6, 4, 4, ZSTD_btlazy2 }, /* level 13.*/ - { 0, 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/ - { 0, 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/ - { 0, 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/ - { 0, 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/ - { 0, 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/ - { 0, 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/ - { 0, 17, 18, 17, 9, 3,256, ZSTD_btopt }, /* level 20.*/ - { 0, 17, 18, 17, 10, 3,256, ZSTD_btopt }, /* level 21.*/ - { 0, 17, 18, 17, 11, 3,256, ZSTD_btopt }, /* level 22.*/ + /* W, C, H, S, L, T, strat */ + { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */ + { 17, 12, 13, 1, 6, 4, ZSTD_fast }, /* level 1 */ + { 17, 13, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */ + { 17, 13, 14, 2, 5, 4, ZSTD_greedy }, /* level 3 */ + { 17, 13, 15, 3, 4, 4, ZSTD_greedy }, /* level 4 */ + { 17, 15, 17, 4, 4, 4, ZSTD_greedy }, /* level 5 */ + { 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ + { 17, 15, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 7 */ + { 17, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */ + { 17, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */ + { 17, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */ + { 17, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */ + { 17, 17, 17, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */ + { 17, 18, 17, 6, 4, 4, ZSTD_btlazy2 }, /* level 13.*/ + { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/ + { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/ + { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/ + { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/ + { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/ + { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/ + { 17, 18, 17, 9, 3,256, ZSTD_btopt }, /* level 20.*/ + { 17, 18, 17, 10, 3,256, ZSTD_btopt }, /* level 21.*/ + { 17, 18, 17, 11, 3,256, ZSTD_btopt }, /* level 22.*/ }, { /* for srcSize <= 16 KB */ - /* l, W, C, H, S, L, T, strat */ - { 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 -- never used */ - { 0, 14, 14, 14, 1, 4, 4, ZSTD_fast }, /* level 1 */ - { 0, 14, 14, 15, 1, 4, 4, ZSTD_fast }, /* level 2 */ - { 0, 14, 14, 14, 4, 4, 4, ZSTD_greedy }, /* level 3.*/ - { 0, 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 4.*/ - { 0, 14, 14, 14, 4, 4, 4, ZSTD_lazy2 }, /* level 5 */ - { 0, 14, 14, 14, 5, 4, 4, ZSTD_lazy2 }, /* level 6 */ - { 0, 14, 14, 14, 6, 4, 4, ZSTD_lazy2 }, /* level 7.*/ - { 0, 14, 14, 14, 7, 4, 4, ZSTD_lazy2 }, /* level 8.*/ - { 0, 14, 15, 14, 6, 4, 4, ZSTD_btlazy2 }, /* level 9.*/ - { 0, 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/ - { 0, 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/ - { 0, 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/ - { 0, 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/ - { 0, 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/ - { 0, 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/ - { 0, 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/ - { 0, 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/ - { 0, 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/ - { 0, 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/ - { 0, 14, 15, 15, 8, 3,256, ZSTD_btopt }, /* level 20.*/ - { 0, 14, 15, 15, 9, 3,256, ZSTD_btopt }, /* level 21.*/ - { 0, 14, 15, 15, 10, 3,256, ZSTD_btopt }, /* level 22.*/ + /* W, C, H, S, L, T, strat */ + { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 -- never used */ + { 14, 14, 14, 1, 4, 4, ZSTD_fast }, /* level 1 */ + { 14, 14, 15, 1, 4, 4, ZSTD_fast }, /* level 2 */ + { 14, 14, 14, 4, 4, 4, ZSTD_greedy }, /* level 3.*/ + { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 4.*/ + { 14, 14, 14, 4, 4, 4, ZSTD_lazy2 }, /* level 5 */ + { 14, 14, 14, 5, 4, 4, ZSTD_lazy2 }, /* level 6 */ + { 14, 14, 14, 6, 4, 4, ZSTD_lazy2 }, /* level 7.*/ + { 14, 14, 14, 7, 4, 4, ZSTD_lazy2 }, /* level 8.*/ + { 14, 15, 14, 6, 4, 4, ZSTD_btlazy2 }, /* level 9.*/ + { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/ + { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/ + { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/ + { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/ + { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/ + { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/ + { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/ + { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/ + { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/ + { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/ + { 14, 15, 15, 8, 3,256, ZSTD_btopt }, /* level 20.*/ + { 14, 15, 15, 9, 3,256, ZSTD_btopt }, /* level 21.*/ + { 14, 15, 15, 10, 3,256, ZSTD_btopt }, /* level 22.*/ }, }; /*! ZSTD_getParams() : * @return ZSTD_parameters structure for a selected compression level and srcSize. * `srcSize` value is optional, select 0 if not known */ -ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSize) +ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, U64 srcSize, size_t dictSize) { - ZSTD_parameters result; - int tableID = ((srcSize-1) <= 256 KB) + ((srcSize-1) <= 128 KB) + ((srcSize-1) <= 16 KB); /* intentional underflow for srcSizeHint == 0 */ + ZSTD_compressionParameters cp; + size_t addedSize = srcSize ? 0 : 500; + U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1; + U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */ if (compressionLevel<=0) compressionLevel = 1; if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL; - result = ZSTD_defaultParameters[tableID][compressionLevel]; - result.srcSize = srcSize; - return result; + cp = ZSTD_defaultCParameters[tableID][compressionLevel]; + if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX; /* auto-correction, for 32-bits mode */ + return cp; } diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index ef99175e8..436058b52 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -325,7 +325,7 @@ size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* zc, const void* src, size_t srcSize) { - size_t result = ZSTD_getFrameParams(&(zc->fParams), src, srcSize); + size_t const result = ZSTD_getFrameParams(&(zc->fParams), src, srcSize); if ((MEM_32bits()) && (zc->fParams.windowLog > 25)) return ERROR(frameParameter_unsupportedBy32bits); return result; } @@ -503,7 +503,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, @return : nb bytes read from src, or an error code if it fails, testable with ZSTD_isError() */ -FORCE_INLINE size_t ZSTD_buildSeqTable(FSE_DTable* DTable, U32 type, U32 rawBits, U32 maxLog, +FORCE_INLINE size_t ZSTD_buildSeqTableOff(FSE_DTable* DTable, U32 type, U32 rawBits, U32 maxLog, const void* src, size_t srcSize) { U32 max = (1< max) return ERROR(corruption_detected); + FSE_buildDTable_rle(DTable, *(const BYTE*)src); /* if *src > max, data is corrupted */ + return 1; + case FSE_ENCODING_RAW : + FSE_buildDTable(DTable, defaultNorm, max, defaultLog); + return 0; + case FSE_ENCODING_STATIC: + return 0; + default : /* impossible */ + case FSE_ENCODING_DYNAMIC : + { U32 tableLog; + S16 norm[MaxSeq+1]; + size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize); + if (FSE_isError(headerSize)) return ERROR(corruption_detected); + if (tableLog > maxLog) return ERROR(corruption_detected); + FSE_buildDTable(DTable, norm, max, tableLog); + return headerSize; + } } +} + + +size_t ZSTD_decodeSeqHeaders(int* nbSeqPtr, + FSE_DTable* DTableLL, FSE_DTable* DTableML, FSE_DTable* DTableOffb, + const void* src, size_t srcSize) { const BYTE* const istart = (const BYTE* const)src; - const BYTE* ip = istart; const BYTE* const iend = istart + srcSize; - U32 LLtype, Offtype, MLtype; + const BYTE* ip = istart; /* check */ if (srcSize < MIN_SEQUENCES_SIZE) return ERROR(srcSize_wrong); /* SeqHead */ - *nbSeq = *ip++; - if (*nbSeq==0) return 1; - if (*nbSeq >= 0x7F) { - if (*nbSeq == 0xFF) - *nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2; - else - *nbSeq = ((nbSeq[0]-0x80)<<8) + *ip++; + { int nbSeq = *ip++; + if (!nbSeq) { *nbSeqPtr=0; return 1; } + if (nbSeq > 0x7F) { + if (nbSeq == 0xFF) + nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2; + else + nbSeq = ((nbSeq-0x80)<<8) + *ip++; + } + *nbSeqPtr = nbSeq; } /* FSE table descriptors */ - LLtype = *ip >> 6; - Offtype = (*ip >> 4) & 3; - MLtype = (*ip >> 2) & 3; - { size_t dumpsLength; - if (*ip & 2) { - dumpsLength = ip[2]; - dumpsLength += ip[1] << 8; - ip += 3; - } else { - dumpsLength = ip[1]; - dumpsLength += (ip[0] & 1) << 8; - ip += 2; + { U32 const LLtype = *ip >> 6; + U32 const Offtype = (*ip >> 4) & 3; + U32 const MLtype = (*ip >> 2) & 3; + ip++; + + /* check */ + if (ip > iend-3) return ERROR(srcSize_wrong); /* min : all 3 are "raw", hence no header, but at least xxLog bits per type */ + + /* Build DTables */ + { size_t const bhSize = ZSTD_buildSeqTable(DTableLL, LLtype, MaxLL, LLFSELog, ip, iend-ip, LL_defaultNorm, LL_defaultNormLog); + if (ZSTD_isError(bhSize)) return ERROR(corruption_detected); + ip += bhSize; } - *dumpsPtr = ip; - ip += dumpsLength; - *dumpsLengthPtr = dumpsLength; - } - - /* check */ - if (ip > iend-3) return ERROR(srcSize_wrong); /* min : all 3 are "raw", hence no header, but at least xxLog bits per type */ - - /* Build DTables */ - { size_t const bhSize = ZSTD_buildSeqTable(DTableLL, LLtype, LLbits, LLFSELog, ip, iend-ip); - if (ZSTD_isError(bhSize)) return ERROR(corruption_detected); - ip += bhSize; - } - { size_t const bhSize = ZSTD_buildSeqTable(DTableOffb, Offtype, Offbits, OffFSELog, ip, iend-ip); - if (ZSTD_isError(bhSize)) return ERROR(corruption_detected); - ip += bhSize; - } - { size_t const bhSize = ZSTD_buildSeqTable(DTableML, MLtype, MLbits, MLFSELog, ip, iend-ip); - if (ZSTD_isError(bhSize)) return ERROR(corruption_detected); - ip += bhSize; - } + { size_t const bhSize = ZSTD_buildSeqTableOff(DTableOffb, Offtype, Offbits, OffFSELog, ip, iend-ip); + if (ZSTD_isError(bhSize)) return ERROR(corruption_detected); + ip += bhSize; + } + { size_t const bhSize = ZSTD_buildSeqTable(DTableML, MLtype, MaxML, MLFSELog, ip, iend-ip, ML_defaultNorm, ML_defaultNormLog); + if (ZSTD_isError(bhSize)) return ERROR(corruption_detected); + ip += bhSize; + } } return ip-istart; } @@ -605,78 +622,58 @@ typedef struct { FSE_DState_t stateOffb; FSE_DState_t stateML; size_t prevOffset; - const BYTE* dumps; - const BYTE* dumpsEnd; } seqState_t; static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState, const U32 mls) { - const BYTE* dumps = seqState->dumps; - const BYTE* const de = seqState->dumpsEnd; - size_t litLength, offset; - /* Literal length */ - litLength = FSE_peakSymbol(&(seqState->stateLL)); - if (litLength == MaxLL) { - const U32 add = *dumps++; - if (add < 255) litLength += add; - else { - litLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no risk : dumps is always followed by seq tables > 1 byte */ - if (litLength&1) litLength>>=1, dumps += 3; - else litLength = (U16)(litLength)>>1, dumps += 2; - } - if (dumps >= de) dumps = de-1; /* late correction, to avoid read overflow (data is now corrupted anyway) */ - } + U32 const llCode = FSE_peekSymbol(&(seqState->stateLL)); + U32 const mlCode = FSE_peekSymbol(&(seqState->stateML)); + U32 const ofCode = FSE_peekSymbol(&(seqState->stateOffb)); /* <= maxOff, by table construction */ - /* Offset */ - { static const U32 offsetPrefix[MaxOff+1] = { - 1 /*fake*/, 1, 2, 4, 8, 0x10, 0x20, 0x40, - 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, - 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, - 0x800000, 0x1000000, 0x2000000, 0x4000000, /*fake*/ 1, 1, 1, 1 }; - U32 const offsetCode = FSE_peakSymbol(&(seqState->stateOffb)); /* <= maxOff, by table construction */ - U32 const nbBits = offsetCode ? offsetCode-1 : 0; - offset = offsetPrefix[offsetCode] + BIT_readBits(&(seqState->DStream), nbBits); + U32 const llBits = LL_bits[llCode]; + U32 const mlBits = ML_bits[mlCode]; + U32 const ofBits = ofCode; + U32 const totalBits = llBits+mlBits+ofBits; + + static const U32 LL_base[MaxLL+1] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 18, 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, + 0x2000, 0x4000, 0x8000, 0x10000 }; + + static const U32 ML_base[MaxML+1] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 34, 36, 38, 40, 44, 48, 56, 64, 80, 96, 0x80, 0x100, 0x200, 0x400, 0x800, + 0x1000, 0x2000, 0x4000, 0x8000, 0x10000 }; + + static const U32 OF_base[MaxOff+1] = { + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, + 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, + 0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, + 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, /*fake*/ 1, 1, 1, 1, 1 }; + + /* sequence */ + { size_t const offset = ofCode ? OF_base[ofCode] + BIT_readBits(&(seqState->DStream), ofBits) : /* <= 26 bits */ + llCode ? seq->offset : seqState->prevOffset; if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream)); - if (offsetCode==0) offset = litLength ? seq->offset : seqState->prevOffset; - if (offsetCode | !litLength) seqState->prevOffset = seq->offset; /* cmove */ - FSE_decodeSymbol(&(seqState->stateOffb), &(seqState->DStream)); /* update */ + if (ofCode | !llCode) seqState->prevOffset = seq->offset; /* cmove */ + seq->offset = offset; } - /* Literal length update */ - FSE_decodeSymbol(&(seqState->stateLL), &(seqState->DStream)); /* update */ - if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream)); + seq->matchLength = ML_base[mlCode] + mls + ((mlCode>31) ? BIT_readBits(&(seqState->DStream), mlBits) : 0); /* <= 16 bits */ + if (MEM_32bits() && (mlBits+llBits>24)) BIT_reloadDStream(&(seqState->DStream)); - /* MatchLength */ - { size_t matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); - if (matchLength == MaxML) { - const U32 add = *dumps++; - if (add < 255) matchLength += add; - else { - matchLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no pb : dumps is always followed by seq tables > 1 byte */ - 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) */ - } - matchLength += mls; - seq->matchLength = matchLength; - } + seq->litLength = LL_base[llCode] + ((llCode>15) ? BIT_readBits(&(seqState->DStream), llBits) : 0); /* <= 16 bits */ + if (MEM_32bits() || + (totalBits > 64 - 7 - (LLFSELog+MLFSELog+OffFSELog)) ) BIT_reloadDStream(&(seqState->DStream)); - /* save result */ - seq->litLength = litLength; - seq->offset = offset; - seqState->dumps = dumps; - -#if 0 /* debug */ - { - static U64 totalDecoded = 0; - printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n", - (U32)(totalDecoded), (U32)litLength, (U32)matchLength, (U32)offset); - totalDecoded += litLength + matchLength; - } -#endif + /* ANS state update */ + FSE_updateState(&(seqState->stateLL), &(seqState->DStream)); /* <= 9 bits */ + FSE_updateState(&(seqState->stateML), &(seqState->DStream)); /* <= 9 bits */ + if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream)); /* <= 18 bits */ + FSE_updateState(&(seqState->stateOffb), &(seqState->DStream)); /* <= 8 bits */ } @@ -685,30 +682,27 @@ FORCE_INLINE size_t ZSTD_execSequence(BYTE* op, const BYTE** litPtr, const BYTE* const litLimit_8, const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd) { - static const int dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; /* added */ - static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 }; /* substracted */ BYTE* const oLitEnd = op + sequence.litLength; - const size_t sequenceLength = sequence.litLength + sequence.matchLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ BYTE* const oend_8 = oend-8; - const BYTE* const litEnd = *litPtr + sequence.litLength; + const BYTE* const iLitEnd = *litPtr + sequence.litLength; const BYTE* match = oLitEnd - sequence.offset; /* check */ if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of 8 from oend */ if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* overwrite beyond dst buffer */ - if (litEnd > litLimit_8) return ERROR(corruption_detected); /* risk read beyond lit buffer */ + if (iLitEnd > litLimit_8) return ERROR(corruption_detected); /* over-read beyond lit buffer */ /* copy Literals */ ZSTD_wildcopy(op, *litPtr, sequence.litLength); /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */ op = oLitEnd; - *litPtr = litEnd; /* update for next sequence */ + *litPtr = iLitEnd; /* update for next sequence */ /* copy Match */ if (sequence.offset > (size_t)(oLitEnd - base)) { /* offset beyond prefix */ - if (sequence.offset > (size_t)(oLitEnd - vBase)) - return ERROR(corruption_detected); + if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected); match = dictEnd - (base-match); if (match + sequence.matchLength <= dictEnd) { memmove(oLitEnd, match, sequence.matchLength); @@ -725,7 +719,9 @@ FORCE_INLINE size_t ZSTD_execSequence(BYTE* op, /* match within prefix */ if (sequence.offset < 8) { /* close range match, overlap */ - const int sub2 = dec64table[sequence.offset]; + static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; /* added */ + static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 }; /* substracted */ + int const sub2 = dec64table[sequence.offset]; op[0] = match[0]; op[1] = match[1]; op[2] = match[2]; @@ -762,12 +758,9 @@ static size_t ZSTD_decompressSequences( BYTE* const ostart = (BYTE* const)dst; BYTE* op = ostart; BYTE* const oend = ostart + maxDstSize; - size_t dumpsLength; const BYTE* litPtr = dctx->litPtr; const BYTE* const litLimit_8 = litPtr + dctx->litBufSize - 8; const BYTE* const litEnd = litPtr + dctx->litSize; - int nbSeq; - const BYTE* dumps; U32* DTableLL = dctx->LLTable; U32* DTableML = dctx->MLTable; U32* DTableOffb = dctx->OffTable; @@ -775,13 +768,14 @@ static size_t ZSTD_decompressSequences( const BYTE* const vBase = (const BYTE*) (dctx->vBase); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); const U32 mls = dctx->fParams.mml; + int nbSeq; /* Build Decoding Tables */ - { size_t const errorCode = ZSTD_decodeSeqHeaders(&nbSeq, &dumps, &dumpsLength, + { size_t const seqHSize = ZSTD_decodeSeqHeaders(&nbSeq, DTableLL, DTableML, DTableOffb, ip, seqSize); - if (ZSTD_isError(errorCode)) return errorCode; - ip += errorCode; + if (ZSTD_isError(seqHSize)) return seqHSize; + ip += seqHSize; } /* Regen sequences */ @@ -791,8 +785,6 @@ static size_t ZSTD_decompressSequences( memset(&sequence, 0, sizeof(sequence)); sequence.offset = REPCODE_STARTVALUE; - seqState.dumps = dumps; - seqState.dumpsEnd = dumps + dumpsLength; seqState.prevOffset = REPCODE_STARTVALUE; { size_t const errorCode = BIT_initDStream(&(seqState.DStream), ip, iend-ip); if (ERR_isError(errorCode)) return ERROR(corruption_detected); } @@ -804,6 +796,13 @@ static size_t ZSTD_decompressSequences( size_t oneSeqSize; nbSeq--; ZSTD_decodeSequence(&sequence, &seqState, mls); +#if 0 /* for debug */ + { U32 pos = (U32)(op-base); + if ((pos > 200802300) && (pos < 200802400)) + printf("Dpos %6u :%5u literals & match %3u bytes at distance %6u \n", + pos, (U32)sequence.litLength, (U32)sequence.matchLength, (U32)sequence.offset); + } +#endif oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litLimit_8, base, vBase, dictEnd); if (ZSTD_isError(oneSeqSize)) return oneSeqSize; op += oneSeqSize; @@ -841,17 +840,16 @@ static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, const void* src, size_t srcSize) { /* blockType == blockCompressed */ const BYTE* ip = (const BYTE*)src; - size_t litCSize; if (srcSize >= ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); ZSTD_LOG_BLOCK("%p: ZSTD_decompressBlock_internal searchLength=%d\n", dctx->base, dctx->fParams.mml); /* Decode literals sub-block */ - litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize); - if (ZSTD_isError(litCSize)) return litCSize; - ip += litCSize; - srcSize -= litCSize; + { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize); + if (ZSTD_isError(litCSize)) return litCSize; + ip += litCSize; + srcSize -= litCSize; } return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize); } @@ -900,7 +898,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, /* Loop on each block */ while (1) { size_t decodedSize=0; - size_t cBlockSize = ZSTD_getcBlockSize(ip, iend-ip, &blockProperties); + size_t const cBlockSize = ZSTD_getcBlockSize(ip, iend-ip, &blockProperties); if (ZSTD_isError(cBlockSize)) return cBlockSize; ip += ZSTD_blockHeaderSize; @@ -1000,7 +998,6 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, co { case ZSTDds_getFrameHeaderSize : { - /* get frame header size */ if (srcSize != ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong); /* impossible */ dctx->headerSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_min); if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; @@ -1014,7 +1011,6 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, co } case ZSTDds_decodeFrameHeader: { - /* get frame header */ size_t result; memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_min, src, dctx->expected); result = ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize); @@ -1025,16 +1021,14 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, co } case ZSTDds_decodeBlockHeader: { - /* Decode block header */ blockProperties_t bp; - size_t blockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp); - if (ZSTD_isError(blockSize)) return blockSize; + size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp); + if (ZSTD_isError(cBlockSize)) return cBlockSize; if (bp.blockType == bt_end) { dctx->expected = 0; dctx->stage = ZSTDds_getFrameHeaderSize; - } - else { - dctx->expected = blockSize; + } else { + dctx->expected = cBlockSize; dctx->bType = bp.blockType; dctx->stage = ZSTDds_decompressBlock; } @@ -1121,7 +1115,7 @@ static size_t ZSTD_loadEntropy(ZSTD_DCtx* dctx, const void* dict, size_t dictSiz static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) { size_t eSize; - U32 magic = MEM_readLE32(dict); + U32 const magic = MEM_readLE32(dict); if (magic != ZSTD_DICT_MAGIC) { /* pure content mode */ ZSTD_refDictContent(dctx, dict, dictSize); @@ -1144,12 +1138,11 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) { - size_t errorCode; - errorCode = ZSTD_decompressBegin(dctx); - if (ZSTD_isError(errorCode)) return errorCode; + { size_t const errorCode = ZSTD_decompressBegin(dctx); + if (ZSTD_isError(errorCode)) return errorCode; } if (dict && dictSize) { - errorCode = ZSTD_decompress_insertDictionary(dctx, dict, dictSize); + size_t const errorCode = ZSTD_decompress_insertDictionary(dctx, dict, dictSize); if (ZSTD_isError(errorCode)) return ERROR(dictionary_corrupted); } diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index c0ff68ea8..49edb3109 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -99,23 +99,39 @@ typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t; #define REPCODE_STARTVALUE 1 #define Litbits 8 -#define MLbits 7 -#define LLbits 6 #define Offbits 5 #define MaxLit ((1<litLengthSum == 0) { ssPtr->litSum = (2<litLengthSum = (1<matchLengthSum = (1<litLengthSum = MaxLL+1; + ssPtr->matchLengthSum = MaxML+1; ssPtr->offCodeSum = (1<matchSum = (2<offCodeSum += ssPtr->offCodeFreq[u]; } } - + ZSTD_setLog2Prices(ssPtr); } @@ -219,12 +219,12 @@ static U32 ZSTD_insertBtAndGetAllMatches ( { const BYTE* const base = zc->base; const U32 current = (U32)(ip-base); - const U32 hashLog = zc->params.hashLog; + const U32 hashLog = zc->params.cParams.hashLog; const size_t h = ZSTD_hashPtr(ip, hashLog, mls); U32* const hashTable = zc->hashTable; U32 matchIndex = hashTable[h]; U32* const bt = zc->contentTable; - const U32 btLog = zc->params.contentLog - 1; + const U32 btLog = zc->params.cParams.contentLog - 1; const U32 btMask= (1U << btLog) - 1; size_t commonLengthSmaller=0, commonLengthLarger=0; const BYTE* const dictBase = zc->dictBase; @@ -244,7 +244,7 @@ static U32 ZSTD_insertBtAndGetAllMatches ( if (minMatch == 3) { /* HC3 match finder */ U32 matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip); - + if (matchIndex3>windowLow && (current - matchIndex3 < (1<<18))) { const BYTE* match; size_t currentMl=0; @@ -409,12 +409,12 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, const BYTE* const ilimit = iend - 8; const BYTE* const base = ctx->base; const BYTE* const prefixStart = base + ctx->dictLimit; - + U32 rep_2=REPCODE_STARTVALUE, rep_1=REPCODE_STARTVALUE; - const U32 maxSearches = 1U << ctx->params.searchLog; - const U32 sufficient_len = ctx->params.targetLength; - const U32 mls = ctx->params.searchLength; - const U32 minMatch = (ctx->params.searchLength == 3) ? 3 : 4; + const U32 maxSearches = 1U << ctx->params.cParams.searchLog; + const U32 sufficient_len = ctx->params.cParams.targetLength; + const U32 mls = ctx->params.cParams.searchLength; + const U32 minMatch = (ctx->params.cParams.searchLength == 3) ? 3 : 4; ZSTD_optimal_t* opt = seqStorePtr->priceTable; ZSTD_match_t* matches = seqStorePtr->matchTable; @@ -734,12 +734,12 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, const BYTE* const dictBase = ctx->dictBase; const BYTE* const dictEnd = dictBase + dictLimit; const U32 lowLimit = ctx->lowLimit; - + U32 rep_2=REPCODE_STARTVALUE, rep_1=REPCODE_STARTVALUE; - const U32 maxSearches = 1U << ctx->params.searchLog; - const U32 sufficient_len = ctx->params.targetLength; - const U32 mls = ctx->params.searchLength; - const U32 minMatch = (ctx->params.searchLength == 3) ? 3 : 4; + const U32 maxSearches = 1U << ctx->params.cParams.searchLog; + const U32 sufficient_len = ctx->params.cParams.targetLength; + const U32 mls = ctx->params.cParams.searchLength; + const U32 minMatch = (ctx->params.cParams.searchLength == 3) ? 3 : 4; ZSTD_optimal_t* opt = seqStorePtr->priceTable; ZSTD_match_t* matches = seqStorePtr->matchTable; @@ -1045,12 +1045,12 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set break; } else { const BYTE* repMatch = dictBase + ((anchor-base) - rep_2); - if ((repMatch + minMatch <= dictEnd) && (MEM_readMINMATCH(anchor, minMatch) == MEM_readMINMATCH(repMatch, minMatch))) + if ((repMatch + minMatch <= dictEnd) && (MEM_readMINMATCH(anchor, minMatch) == MEM_readMINMATCH(repMatch, minMatch))) mlen = (U32)ZSTD_count_2segments(anchor+minMatch, repMatch+minMatch, iend, dictEnd, prefixStart) + minMatch; else break; } - + offset = rep_2; rep_2 = rep_1; rep_1 = offset; /* swap offset history */ ZSTD_LOG_ENCODE("%d/%d: ENCODE REP literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(anchor-base), (int)(iend-base), (int)(0), (int)best_mlen, (int)(0), (int)rep_1, (int)rep_2); ZSTD_updatePrice(seqStorePtr, 0, anchor, 0, mlen-minMatch); diff --git a/lib/zstd_static.h b/lib/zstd_static.h index d88fbce82..52d7193ef 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -57,7 +57,7 @@ extern "C" { /*-************************************* * Types ***************************************/ -#define ZSTD_WINDOWLOG_MAX 27 +#define ZSTD_WINDOWLOG_MAX (MEM_32bits() ? 25 : 27) #define ZSTD_WINDOWLOG_MIN 18 #define ZSTD_CONTENTLOG_MAX (ZSTD_WINDOWLOG_MAX+1) #define ZSTD_CONTENTLOG_MIN 4 @@ -76,7 +76,6 @@ extern "C" { typedef enum { ZSTD_fast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2, ZSTD_btopt } ZSTD_strategy; typedef struct { - U64 srcSize; /* optional : tells how much bytes are present in the frame. Use 0 if not known. */ U32 windowLog; /* largest match distance : larger == more compression, more memory needed during decompression */ U32 contentLog; /* full search segment : larger == more compression, slower, more memory (useless for fast) */ U32 hashLog; /* dispatch table : larger == faster, more memory */ @@ -84,6 +83,15 @@ typedef struct { U32 searchLength; /* match length searched : larger == faster decompression, sometimes less compression */ U32 targetLength; /* acceptable match size for optimal parser (only) : larger == more compression, slower */ ZSTD_strategy strategy; +} ZSTD_compressionParameters; + +typedef struct { + U32 contentSizeFlag; /* 1: content size will be in frame header (if known). */ +} ZSTD_frameParameters; + +typedef struct { + ZSTD_compressionParameters cParams; + ZSTD_frameParameters fParams; } ZSTD_parameters; @@ -92,14 +100,19 @@ typedef struct { ***************************************/ ZSTDLIB_API unsigned ZSTD_maxCLevel (void); -/*! ZSTD_getParams() : -* @return ZSTD_parameters structure for a selected compression level and srcSize. +/*! ZSTD_getCParams() : +* @return ZSTD_compressionParameters structure for a selected compression level and srcSize. * `srcSize` value is optional, select 0 if not known */ -ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSize); +ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, U64 srcSize, size_t dictSize); -/*! ZSTD_validateParams() : -* correct params value to remain within authorized range */ -ZSTDLIB_API void ZSTD_validateParams(ZSTD_parameters* params); +/*! ZSTD_checkParams() : +* Ensure param values remain within authorized range */ +ZSTDLIB_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); + +/*! ZSTD_adjustParams() : +* optimize params for a given `srcSize` and `dictSize`. +* both values are optional, select `0` if unknown. */ +ZSTDLIB_API void ZSTD_adjustCParams(ZSTD_compressionParameters* params, U64 srcSize, size_t dictSize); /*! ZSTD_compress_advanced() : * Same as ZSTD_compress_usingDict(), with fine-tune control of each compression parameter */ @@ -137,7 +150,7 @@ ZSTDLIB_API size_t ZSTD_decompress_usingPreparedDCtx( ****************************************/ 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_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, U64 pledgedSrcSize); 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); diff --git a/programs/bench.c b/programs/bench.c index dec575893..cea9634c2 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -58,16 +58,16 @@ # include /* setpriority */ # define BMK_sleep(s) sleep(s) # define mili_sleep(mili) { struct timespec t; t.tv_sec=0; t.tv_nsec=mili*1000000ULL; nanosleep(&t, NULL); } -# define setHighPriority() setpriority(PRIO_PROCESS, 0, -20) +# define SET_HIGH_PRIORITY setpriority(PRIO_PROCESS, 0, -20) #elif defined(_WIN32) # include # define BMK_sleep(s) Sleep(1000*s) # define mili_sleep(mili) Sleep(mili) -# define setHighPriority() SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS) +# define SET_HIGH_PRIORITY SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS) #else # define BMK_sleep(s) /* disabled */ # define mili_sleep(mili) /* disabled */ -# define setHighPriority() /* disabled */ +# define SET_HIGH_PRIORITY /* disabled */ #endif #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) @@ -97,6 +97,7 @@ #include "xxhash.h" + /* ************************************* * Compiler specifics ***************************************/ @@ -238,18 +239,16 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, const size_t* fileSizes, U32 nbFiles, const void* dictBuffer, size_t dictBufferSize, benchResult_t *result) { - const size_t blockSize = (g_blockSize ? g_blockSize : srcSize) + (!srcSize); /* avoid div by 0 */ - const U32 maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles; + size_t const blockSize = (g_blockSize ? g_blockSize : srcSize) + (!srcSize); /* avoid div by 0 */ + U32 const maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles; blockParam_t* const blockTable = (blockParam_t*) malloc(maxNbBlocks * sizeof(blockParam_t)); - const size_t maxCompressedSize = ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024); /* add some room for safety */ + size_t const maxCompressedSize = ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024); /* add some room for safety */ void* const compressedBuffer = malloc(maxCompressedSize); void* const resultBuffer = malloc(srcSize); ZSTD_CCtx* refCtx = ZSTD_createCCtx(); ZSTD_CCtx* ctx = ZSTD_createCCtx(); ZSTD_DCtx* refDCtx = ZSTD_createDCtx(); ZSTD_DCtx* dctx = ZSTD_createDCtx(); - - U64 const crcOrig = XXH64(srcBuffer, srcSize, 0); U32 nbBlocks; BMK_time_t ticksPerSecond; @@ -287,20 +286,19 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.50, 1); /* Bench */ - { size_t cSize = 0; - double fastestC = 100000000., fastestD = 100000000.; - double ratio = 0.; + { double fastestC = 100000000., fastestD = 100000000.; + U64 const crcOrig = XXH64(srcBuffer, srcSize, 0); U64 crcCheck = 0; BMK_time_t coolTime; U32 testNb; + size_t cSize = 0; + double ratio = 0.; BMK_getTime(coolTime); DISPLAYLEVEL(2, "\r%79s\r", ""); for (testNb = 1; testNb <= (g_nbIterations + !g_nbIterations); testNb++) { - int nbLoops; BMK_time_t clockStart, clockEnd; - U64 clockSpan; - U64 const clockLoop = g_nbIterations ? TIMELOOP_S*1000000ULL : 10; + U64 clockLoop = g_nbIterations ? TIMELOOP_S*1000000ULL : 10; /* overheat protection */ if (BMK_clockSpan(coolTime, ticksPerSecond) > ACTIVEPERIOD_S*1000000ULL) { @@ -319,19 +317,22 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, while (BMK_getSpanTimeNano(ticksPerSecond, clockStart, clockEnd) == 0); BMK_getTime(clockStart); - for (nbLoops = 0 ; BMK_clockSpan(clockStart, ticksPerSecond) < clockLoop ; nbLoops++) { - U32 blockNb; - ZSTD_compressBegin_targetSrcSize(refCtx, dictBuffer, dictBufferSize, blockSize, cLevel); - for (blockNb=0; blockNb%10u (%5.3f),%6.1f MB/s ,%6.1f MB/s\r", testNb, displayName, (U32)srcSize, (U32)cSize, ratio, (double)srcSize / fastestC, (double)srcSize / fastestD ); /* CRC Checking */ -_findError: - crcCheck = XXH64(resultBuffer, srcSize, 0); - if (crcOrig!=crcCheck) { - size_t u; - DISPLAY("\n!!! WARNING !!! %14s : Invalid Checksum : %x != %x\n", displayName, (unsigned)crcOrig, (unsigned)crcCheck); - for (u=0; u u) break; - bacc += blockTable[segNb].srcSize; + { crcCheck = XXH64(resultBuffer, srcSize, 0); + if (crcOrig!=crcCheck) { + size_t u; + DISPLAY("!!! WARNING !!! %14s : Invalid Checksum : %x != %x \n", displayName, (unsigned)crcOrig, (unsigned)crcCheck); + for (u=0; u u) break; + bacc += blockTable[segNb].srcSize; + } + pos = (U32)(u - bacc); + bNb = pos / (128 KB); + DISPLAY("(block %u, sub %u, pos %u) \n", segNb, bNb, pos); + break; } - pos = (U32)(u - bacc); - bNb = pos / (128 KB); - printf("(block %u, sub %u, pos %u) \n", segNb, bNb, pos); - break; - } - if (u==srcSize-1) { /* should never happen */ - printf("no difference detected\n"); - } } - break; - } /* if (crcOrig!=crcCheck) */ + if (u==srcSize-1) { /* should never happen */ + DISPLAY("no difference detected\n"); + } } + break; + } } /* CRC Checking */ #endif } /* for (testNb = 1; testNb <= (g_nbIterations + !g_nbIterations); testNb++) */ @@ -445,7 +449,7 @@ static void BMK_benchCLevel(void* srcBuffer, size_t benchedSize, benchResult_t result, total; int l; - setHighPriority(); + SET_HIGH_PRIORITY; const char* pch = strrchr(displayName, '\\'); /* Windows */ if (!pch) pch = strrchr(displayName, '/'); /* Linux */ @@ -494,23 +498,25 @@ static U64 BMK_getTotalFileSize(const char** fileNamesTable, unsigned nbFiles) return total; } +/*! BMK_loadFiles() : + Loads `buffer` with content of files listed within `fileNamesTable`. + At most, fills `buffer` entirely */ static void BMK_loadFiles(void* buffer, size_t bufferSize, size_t* fileSizes, - const char** fileNamesTable, unsigned const nbFiles) + const char** fileNamesTable, unsigned nbFiles) { size_t pos = 0; unsigned n; for (n=0; n bufferSize-pos) fileSize = bufferSize-pos; - readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f); - if (readSize != (size_t)fileSize) EXM_THROW(11, "could not read %s", fileNamesTable[n]); - pos += readSize; + if (fileSize > bufferSize-pos) fileSize = bufferSize-pos, nbFiles=n; /* buffer too small - stop after this file */ + { size_t const readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f); + if (readSize != (size_t)fileSize) EXM_THROW(11, "could not read %s", fileNamesTable[n]); + pos += readSize; } fileSizes[n] = (size_t)fileSize; fclose(f); } diff --git a/programs/fileio.c b/programs/fileio.c index 907d990a1..d5893f1a6 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -333,28 +333,28 @@ static int FIO_compressFilename_internal(cRess_t ress, { FILE* srcFile = ress.srcFile; FILE* dstFile = ress.dstFile; - U64 filesize = 0; + U64 readsize = 0; U64 compressedfilesize = 0; size_t dictSize = ress.dictBufferSize; - size_t sizeCheck, errorCode; + size_t sizeCheck; ZSTD_parameters params; + U64 const fileSize = FIO_getFileSize(srcFileName); /* init */ - filesize = MAX(FIO_getFileSize(srcFileName),dictSize); - 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)); + params.cParams = ZSTD_getCParams(cLevel, fileSize, dictSize); + params.fParams.contentSizeFlag = 1; + if (g_maxWLog) if (params.cParams.windowLog > g_maxWLog) params.cParams.windowLog = g_maxWLog; + { size_t const errorCode = ZBUFF_compressInit_advanced(ress.ctx, ress.dictBuffer, ress.dictBufferSize, params, fileSize); + if (ZBUFF_isError(errorCode)) EXM_THROW(21, "Error initializing compression : %s", ZBUFF_getErrorName(errorCode)); } /* Main compression loop */ - filesize = 0; + readsize = 0; while (1) { /* Fill input Buffer */ - size_t inSize = fread(ress.srcBuffer, (size_t)1, ress.srcBufferSize, srcFile); + size_t const inSize = fread(ress.srcBuffer, (size_t)1, ress.srcBufferSize, srcFile); if (inSize==0) break; - filesize += inSize; - DISPLAYUPDATE(2, "\rRead : %u MB ", (U32)(filesize>>20)); + readsize += inSize; + DISPLAYUPDATE(2, "\rRead : %u MB ", (U32)(readsize>>20)); { /* Compress using buffered streaming */ size_t usedInSize = inSize; @@ -371,13 +371,12 @@ static int FIO_compressFilename_internal(cRess_t ress, if (sizeCheck!=cSize) EXM_THROW(25, "Write error : cannot write compressed block into %s", dstFileName); compressedfilesize += cSize; } - DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%% ", (U32)(filesize>>20), (double)compressedfilesize/filesize*100); + DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%% ", (U32)(readsize>>20), (double)compressedfilesize/readsize*100); } /* End of Frame */ - { - size_t cSize = ress.dstBufferSize; - size_t result = ZBUFF_compressEnd(ress.ctx, ress.dstBuffer, &cSize); + { size_t cSize = ress.dstBufferSize; + size_t const result = ZBUFF_compressEnd(ress.ctx, ress.dstBuffer, &cSize); if (result!=0) EXM_THROW(26, "Compression error : cannot create frame end"); sizeCheck = fwrite(ress.dstBuffer, 1, cSize, dstFile); @@ -388,7 +387,7 @@ static int FIO_compressFilename_internal(cRess_t ress, /* Status */ DISPLAYLEVEL(2, "\r%79s\r", ""); DISPLAYLEVEL(2,"Compressed %llu bytes into %llu bytes ==> %.2f%%\n", - (unsigned long long) filesize, (unsigned long long) compressedfilesize, (double)compressedfilesize/filesize*100); + (unsigned long long)readsize, (unsigned long long) compressedfilesize, (double)compressedfilesize/readsize*100); return 0; } diff --git a/programs/fullbench.c b/programs/fullbench.c index 24cf95d39..751966562 100644 --- a/programs/fullbench.c +++ b/programs/fullbench.c @@ -118,7 +118,7 @@ static clock_t BMK_clockSpan( clock_t clockStart ) static size_t BMK_findMaxMem(U64 requiredMem) { - const size_t step = 64 MB; + size_t const step = 64 MB; void* testmem = NULL; requiredMem = (((requiredMem >> 26) + 1) << 26); @@ -182,15 +182,13 @@ size_t local_ZSTD_decodeLiteralsBlock(void* dst, size_t dstSize, void* buff2, co } 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); +extern size_t ZSTD_decodeSeqHeaders(int* nbSeq, 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) { 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 */ - const BYTE* dumps; - size_t length; int nbSeq; (void)src; (void)srcSize; (void)dst; (void)dstSize; - return ZSTD_decodeSeqHeaders(&nbSeq, &dumps, &length, DTableLL, DTableML, DTableOffb, buff2, g_cSize); + return ZSTD_decodeSeqHeaders(&nbSeq, DTableLL, DTableML, DTableOffb, buff2, g_cSize); } diff --git a/programs/fuzzer.c b/programs/fuzzer.c index d53586c17..29bf4861d 100644 --- a/programs/fuzzer.c +++ b/programs/fuzzer.c @@ -488,12 +488,12 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 maxDuration, doub if (cSize > 3) { const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */ const size_t tooSmallSize = cSize - missing; - static const U32 endMark = 0x4DC2B1A9; + const U32 endMark = 0x4DC2B1A9; memcpy(dstBuffer+tooSmallSize, &endMark, 4); errorCode = ZSTD_compressCCtx(ctx, dstBuffer, tooSmallSize, sampleBuffer, sampleSize, cLevel); CHECK(!ZSTD_isError(errorCode), "ZSTD_compressCCtx should have failed ! (buffer too small : %u < %u)", (U32)tooSmallSize, (U32)cSize); { U32 endCheck; memcpy(&endCheck, dstBuffer+tooSmallSize, 4); - CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow"); } + CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow"); } } /* frame header decompression test */ diff --git a/programs/paramgrill.c b/programs/paramgrill.c index 1b55f11c9..bd316583e 100644 --- a/programs/paramgrill.c +++ b/programs/paramgrill.c @@ -126,7 +126,7 @@ static U32 g_rand = 1; static U32 g_singleRun = 0; static U32 g_target = 0; static U32 g_noSeed = 0; -static ZSTD_parameters g_params = { 0, 0, 0, 0, 0, 0, 0, ZSTD_greedy }; +static ZSTD_compressionParameters g_params = { 0, 0, 0, 0, 0, 0, ZSTD_greedy }; void BMK_SetNbIterations(int nbLoops) { @@ -251,7 +251,7 @@ typedef struct static size_t BMK_benchParam(BMK_result_t* resultPtr, const void* srcBuffer, size_t srcSize, ZSTD_CCtx* ctx, - const ZSTD_parameters params) + const ZSTD_compressionParameters cParams) { const size_t blockSize = g_blockSize ? g_blockSize : srcSize; const U32 nbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize); @@ -259,13 +259,14 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr, const size_t maxCompressedSize = (size_t)nbBlocks * ZSTD_compressBound(blockSize); void* const compressedBuffer = malloc(maxCompressedSize); void* const resultBuffer = malloc(srcSize); - U32 Wlog = params.windowLog; - U32 Clog = params.contentLog; - U32 Hlog = params.hashLog; - U32 Slog = params.searchLog; - U32 Slength = params.searchLength; - U32 Tlength = params.targetLength; - ZSTD_strategy strat = params.strategy; + ZSTD_parameters params; + U32 Wlog = cParams.windowLog; + U32 Clog = cParams.contentLog; + U32 Hlog = cParams.hashLog; + U32 Slog = cParams.searchLog; + U32 Slength = cParams.searchLength; + U32 Tlength = cParams.targetLength; + ZSTD_strategy strat = cParams.strategy; char name[30] = { 0 }; U64 crcOrig; @@ -315,6 +316,8 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr, const int startTime =BMK_GetMilliStart(); DISPLAY("\r%79s\r", ""); + params.cParams = cParams; + params.fParams.contentSizeFlag = 0; for (loopNb = 1; loopNb <= g_nbIterations; loopNb++) { int nbLoops; int milliTime; @@ -407,11 +410,11 @@ const char* g_stratName[] = { "ZSTD_fast ", "ZSTD_btlazy2", "ZSTD_btopt " }; -static void BMK_printWinner(FILE* f, U32 cLevel, BMK_result_t result, ZSTD_parameters params, size_t srcSize) +static void BMK_printWinner(FILE* f, U32 cLevel, BMK_result_t result, ZSTD_compressionParameters params, size_t srcSize) { DISPLAY("\r%79s\r", ""); - fprintf(f," {%3u,%3u,%3u,%3u,%3u,%3u,%3u, %s }, ", - 0, params.windowLog, params.contentLog, params.hashLog, params.searchLog, params.searchLength, + fprintf(f," {%3u,%3u,%3u,%3u,%3u,%3u, %s }, ", + params.windowLog, params.contentLog, params.hashLog, params.searchLog, params.searchLength, params.targetLength, g_stratName[(U32)(params.strategy)]); fprintf(f, "/* level %2u */ /* R:%5.3f at %5.1f MB/s - %5.1f MB/s */\n", @@ -423,7 +426,7 @@ static U32 g_cSpeedTarget[NB_LEVELS_TRACKED] = { 0 }; /* NB_LEVELS_TRACKED : c typedef struct { BMK_result_t result; - ZSTD_parameters params; + ZSTD_compressionParameters params; } winnerInfo_t; static void BMK_printWinners2(FILE* f, const winnerInfo_t* winners, size_t srcSize) @@ -431,7 +434,7 @@ static void BMK_printWinners2(FILE* f, const winnerInfo_t* winners, size_t srcSi unsigned cLevel; fprintf(f, "\n /* Proposed configurations : */ \n"); - fprintf(f, " /* l, W, C, H, S, L, T, strat */ \n"); + fprintf(f, " /* W, C, H, S, L, T, strat */ \n"); for (cLevel=0; cLevel <= ZSTD_maxCLevel(); cLevel++) BMK_printWinner(f, cLevel, winners[cLevel].result, winners[cLevel].params, srcSize); @@ -446,9 +449,9 @@ static void BMK_printWinners(FILE* f, const winnerInfo_t* winners, size_t srcSiz BMK_printWinners2(stdout, winners, srcSize); } -size_t ZSTD_sizeofCCtx(ZSTD_parameters params); /* hidden interface, declared here */ +size_t ZSTD_sizeofCCtx(ZSTD_compressionParameters params); /* hidden interface, declared here */ -static int BMK_seed(winnerInfo_t* winners, const ZSTD_parameters params, +static int BMK_seed(winnerInfo_t* winners, const ZSTD_compressionParameters params, const void* srcBuffer, size_t srcSize, ZSTD_CCtx* ctx) { @@ -541,7 +544,7 @@ static int BMK_seed(winnerInfo_t* winners, const ZSTD_parameters params, /* nullified useless params, to ensure count stats */ -static ZSTD_parameters* sanitizeParams(ZSTD_parameters params) +static ZSTD_compressionParameters* sanitizeParams(ZSTD_compressionParameters params) { g_params = params; if (params.strategy == ZSTD_fast) @@ -552,44 +555,50 @@ static ZSTD_parameters* sanitizeParams(ZSTD_parameters params) } -static void paramVariation(ZSTD_parameters* p) +static void paramVariation(ZSTD_compressionParameters* ptr) { - U32 nbChanges = (FUZ_rand(&g_rand) & 3) + 1; - for (; nbChanges; nbChanges--) { - const U32 changeID = FUZ_rand(&g_rand) % 14; - switch(changeID) - { - case 0: - p->contentLog++; break; - case 1: - p->contentLog--; break; - case 2: - p->hashLog++; break; - case 3: - p->hashLog--; break; - case 4: - p->searchLog++; break; - case 5: - p->searchLog--; break; - case 6: - p->windowLog++; break; - case 7: - p->windowLog--; break; - case 8: - p->searchLength++; break; - case 9: - p->searchLength--; break; - case 10: - p->strategy = (ZSTD_strategy)(((U32)p->strategy)+1); break; - case 11: - p->strategy = (ZSTD_strategy)(((U32)p->strategy)-1); break; - case 12: - p->targetLength *= 1 + ((double)(FUZ_rand(&g_rand)&255)) / 256.; break; - case 13: - p->targetLength /= 1 + ((double)(FUZ_rand(&g_rand)&255)) / 256.; break; + ZSTD_compressionParameters p; + U32 validated = 0; + while (!validated) { + U32 nbChanges = (FUZ_rand(&g_rand) & 3) + 1; + p = *ptr; + for ( ; nbChanges ; nbChanges--) { + const U32 changeID = FUZ_rand(&g_rand) % 14; + switch(changeID) + { + case 0: + p.contentLog++; break; + case 1: + p.contentLog--; break; + case 2: + p.hashLog++; break; + case 3: + p.hashLog--; break; + case 4: + p.searchLog++; break; + case 5: + p.searchLog--; break; + case 6: + p.windowLog++; break; + case 7: + p.windowLog--; break; + case 8: + p.searchLength++; break; + case 9: + p.searchLength--; break; + case 10: + p.strategy = (ZSTD_strategy)(((U32)p.strategy)+1); break; + case 11: + p.strategy = (ZSTD_strategy)(((U32)p.strategy)-1); break; + case 12: + p.targetLength *= 1 + ((double)(FUZ_rand(&g_rand)&255)) / 256.; break; + case 13: + p.targetLength /= 1 + ((double)(FUZ_rand(&g_rand)&255)) / 256.; break; + } } + validated = !ZSTD_isError(ZSTD_checkCParams(p)); } - ZSTD_validateParams(p); + *ptr = p; } @@ -605,7 +614,7 @@ static BYTE g_alreadyTested[PARAMTABLESIZE] = {0}; /* init to zero */ #define MAX(a,b) ( (a) > (b) ? (a) : (b) ) static void playAround(FILE* f, winnerInfo_t* winners, - ZSTD_parameters params, + ZSTD_compressionParameters params, const void* srcBuffer, size_t srcSize, ZSTD_CCtx* ctx) { @@ -613,7 +622,7 @@ static void playAround(FILE* f, winnerInfo_t* winners, const int startTime = BMK_GetMilliStart(); while (BMK_GetMilliSpan(startTime) < g_maxVariationTime) { - ZSTD_parameters p = params; + ZSTD_compressionParameters p = params; if (nbVariations++ > g_maxNbVariations) break; paramVariation(&p); @@ -634,10 +643,12 @@ static void playAround(FILE* f, winnerInfo_t* winners, } -static void potentialRandomParams(ZSTD_parameters* p, U32 inverseChance) +static void potentialRandomParams(ZSTD_compressionParameters* p, U32 inverseChance) { U32 chance = (FUZ_rand(&g_rand) % (inverseChance+1)); - if (!chance) { + U32 validated = 0; + if (!chance) + while (!validated) { /* totally random entry */ p->contentLog = FUZ_rand(&g_rand) % (ZSTD_CONTENTLOG_MAX+1 - ZSTD_CONTENTLOG_MIN) + ZSTD_CONTENTLOG_MIN; p->hashLog = FUZ_rand(&g_rand) % (ZSTD_HASHLOG_MAX+1 - ZSTD_HASHLOG_MIN) + ZSTD_HASHLOG_MIN; @@ -646,7 +657,7 @@ static void potentialRandomParams(ZSTD_parameters* p, U32 inverseChance) p->searchLength=FUZ_rand(&g_rand) % (ZSTD_SEARCHLENGTH_MAX+1 - ZSTD_SEARCHLENGTH_MIN) + ZSTD_SEARCHLENGTH_MIN; p->targetLength=FUZ_rand(&g_rand) % (ZSTD_TARGETLENGTH_MAX+1 - ZSTD_TARGETLENGTH_MIN) + ZSTD_TARGETLENGTH_MIN; p->strategy = (ZSTD_strategy) (FUZ_rand(&g_rand) % (ZSTD_btopt +1)); - ZSTD_validateParams(p); + validated = !ZSTD_isError(ZSTD_checkCParams(*p)); } } @@ -658,10 +669,9 @@ static void BMK_selectRandomStart( U32 id = (FUZ_rand(&g_rand) % (ZSTD_maxCLevel()+1)); if ((id==0) || (winners[id].params.windowLog==0)) { /* totally random entry */ - ZSTD_parameters p; + ZSTD_compressionParameters p; potentialRandomParams(&p, 1); - p.srcSize = srcSize; - ZSTD_validateParams(&p); + ZSTD_adjustCParams(&p, srcSize, 0); playAround(f, winners, p, srcBuffer, srcSize, ctx); } else @@ -672,7 +682,7 @@ static void BMK_selectRandomStart( static void BMK_benchMem(void* srcBuffer, size_t srcSize) { ZSTD_CCtx* ctx = ZSTD_createCCtx(); - ZSTD_parameters params; + ZSTD_compressionParameters params; winnerInfo_t winners[NB_LEVELS_TRACKED]; int i; unsigned u; @@ -682,8 +692,7 @@ static void BMK_benchMem(void* srcBuffer, size_t srcSize) if (g_singleRun) { BMK_result_t testResult; - g_params.srcSize = blockSize; - ZSTD_validateParams(&g_params); + ZSTD_adjustCParams(&g_params, srcSize, 0); BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, g_params); DISPLAY("\n"); return; @@ -699,7 +708,7 @@ static void BMK_benchMem(void* srcBuffer, size_t srcSize) else { /* baseline config for level 1 */ BMK_result_t testResult; - params = ZSTD_getParams(1, blockSize); + params = ZSTD_getCParams(1, blockSize, 0); BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, params); g_cSpeedTarget[1] = (testResult.cSpeed * 31) >> 5; } @@ -712,8 +721,7 @@ static void BMK_benchMem(void* srcBuffer, size_t srcSize) { const int maxSeeds = g_noSeed ? 1 : ZSTD_maxCLevel(); for (i=1; i<=maxSeeds; i++) { - params = ZSTD_getParams(i, blockSize); - ZSTD_validateParams(¶ms); + params = ZSTD_getCParams(i, blockSize, 0); BMK_seed(winners, params, srcBuffer, srcSize, ctx); } } @@ -864,7 +872,7 @@ int optimizeForSize(char* inFileName) { ZSTD_CCtx* ctx = ZSTD_createCCtx(); - ZSTD_parameters params; + ZSTD_compressionParameters params; winnerInfo_t winner; BMK_result_t candidate; const size_t blockSize = g_blockSize ? g_blockSize : benchedSize; @@ -878,7 +886,7 @@ int optimizeForSize(char* inFileName) { const int maxSeeds = g_noSeed ? 1 : ZSTD_maxCLevel(); for (i=1; i<=maxSeeds; i++) { - params = ZSTD_getParams(i, blockSize); + params = ZSTD_getCParams(i, blockSize, 0); BMK_benchParam(&candidate, origBuff, benchedSize, ctx, params); if ( (candidate.cSize < winner.result.cSize) ||((candidate.cSize == winner.result.cSize) && (candidate.cSpeed > winner.result.cSpeed)) ) @@ -1028,7 +1036,7 @@ int main(int argc, char** argv) case 'S': g_singleRun = 1; argument++; - g_params = ZSTD_getParams(2, g_blockSize); + g_params = ZSTD_getCParams(2, g_blockSize, 0); for ( ; ; ) { switch(*argument) { @@ -1079,7 +1087,7 @@ int main(int argc, char** argv) argument++; while ((*argument>= '0') && (*argument<='9')) cLevel *= 10, cLevel += *argument++ - '0'; - g_params = ZSTD_getParams(cLevel, g_blockSize); + g_params = ZSTD_getCParams(cLevel, g_blockSize, 0); continue; } default : ; diff --git a/programs/playTests.sh b/programs/playTests.sh index 444d91ebe..2163e3ff9 100755 --- a/programs/playTests.sh +++ b/programs/playTests.sh @@ -25,7 +25,9 @@ roundTripTest() { echo "\n**** simple tests **** " ./datagen > tmp -$ZSTD tmp +echo -n "trivial compression : " +$ZSTD -f tmp +echo "OK" $ZSTD -99 tmp && die "too large compression level undetected" $ZSTD tmp -c > tmpCompressed $ZSTD tmp --stdout > tmpCompressed @@ -71,6 +73,11 @@ echo "\n**** dictionary tests **** " ./datagen -g1M | md5sum > tmp1 ./datagen -g1M | $ZSTD -D tmpDict | $ZSTD -D tmpDict -dvq | md5sum > tmp2 diff -q tmp1 tmp2 +$ZSTD --train *.c *.h -o tmpDict +$ZSTD xxhash.c -D tmpDict -of tmp +$ZSTD -d tmp -D tmpDict -of result +diff xxhash.c result + echo "\n**** multiple files tests **** " @@ -106,6 +113,10 @@ $ZSTD -t * && die "bad files not detected !" echo "\n**** zstd round-trip tests **** " roundTripTest +roundTripTest -g15K # TableID==3 +roundTripTest -g127K # TableID==2 +roundTripTest -g255K # TableID==1 +roundTripTest -g513K # TableID==0 roundTripTest -g512K 6 # greedy, hash chain roundTripTest -g512K 16 # btlazy2 roundTripTest -g512K 19 # btopt diff --git a/programs/zbufftest.c b/programs/zbufftest.c index aa57b576a..f44f5d5e5 100644 --- a/programs/zbufftest.c +++ b/programs/zbufftest.c @@ -1,6 +1,6 @@ /* Fuzzer test tool for zstd_buffered - Copyright (C) Yann Collet 2105 + Copyright (C) Yann Collet 2015-2016 GPL v2 License @@ -19,11 +19,10 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You can contact the author at : - - ZSTD source repository : https://github.com/Cyan4973/zstd - - ZSTD public forum : https://groups.google.com/forum/#!forum/lz4c + - ZSTD homepage : https://www.zstd.net/ */ -/************************************** +/*-************************************ * Compiler specific **************************************/ #ifdef _MSC_VER /* Visual Studio */ @@ -33,7 +32,7 @@ #endif -/************************************** +/*-************************************ * Includes **************************************/ #include /* free */ @@ -42,13 +41,13 @@ #include /* strcmp */ #include "mem.h" #include "zbuff.h" -#include "zstd.h" /* ZSTD_compressBound() */ +#include "zstd_static.h" /* ZSTD_compressBound(), ZSTD_maxCLevel() */ #include "datagen.h" /* RDG_genBuffer */ #include "xxhash.h" /* XXH64 */ -/************************************** - Constants +/*-************************************ +* Constants **************************************/ #ifndef ZSTD_VERSION # define ZSTD_VERSION "" @@ -66,7 +65,7 @@ static const U32 prime2 = 2246822519U; -/************************************** +/*-************************************ * Display Macros **************************************/ #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) @@ -83,7 +82,7 @@ static U32 g_displayTime = 0; static U32 g_testTime = 0; -/********************************************************* +/*-******************************************************* * Fuzzer functions *********************************************************/ #define MAX(a,b) ((a)>(b)?(a):(b)) @@ -107,15 +106,17 @@ static U32 FUZ_GetMilliSpan(U32 nTimeStart) return nSpan; } - +/*! FUZ_rand() : + @return : a 27 bits random value, from a 32-bits `seed`. + `seed` is also modified */ # define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r))) -unsigned int FUZ_rand(unsigned int* src) +unsigned int FUZ_rand(unsigned int* seedPtr) { - U32 rand32 = *src; + U32 rand32 = *seedPtr; rand32 *= prime1; rand32 += prime2; rand32 = FUZ_rotl32(rand32, 13); - *src = rand32; + *seedPtr = rand32; return rand32 >> 5; } @@ -133,12 +134,12 @@ static unsigned FUZ_highbit32(U32 v32) static int basicUnitTests(U32 seed, double compressibility) { int testResult = 0; - void* CNBuffer; size_t CNBufferSize = COMPRESSIBLE_NOISE_LENGTH; - void* compressedBuffer; - size_t compressedBufferSize = ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH); - void* decodedBuffer; - size_t decodedBufferSize = CNBufferSize; + void* CNBuffer = malloc(CNBufferSize); + size_t const compressedBufferSize = ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH); + void* compressedBuffer = malloc(compressedBufferSize); + size_t const decodedBufferSize = CNBufferSize; + void* decodedBuffer = malloc(decodedBufferSize); U32 randState = seed; size_t result, cSize, readSize, genSize; U32 testNb=0; @@ -146,11 +147,7 @@ static int basicUnitTests(U32 seed, double compressibility) ZBUFF_DCtx* zd = ZBUFF_createDCtx(); /* Create compressible test buffer */ - CNBuffer = malloc(CNBufferSize); - compressedBuffer = malloc(compressedBufferSize); - decodedBuffer = malloc(decodedBufferSize); - if (!CNBuffer || !compressedBuffer || !decodedBuffer || !zc || !zd) - { + if (!CNBuffer || !compressedBuffer || !decodedBuffer || !zc || !zd) { DISPLAY("Not enough memory, aborting\n"); goto _output_error; } @@ -183,11 +180,9 @@ static int basicUnitTests(U32 seed, double compressibility) DISPLAYLEVEL(4, "OK \n"); /* check regenerated data is byte exact */ - { - size_t i; + { size_t i; DISPLAYLEVEL(4, "test%3i : check decompressed result : ", testNb++); - for (i=0; i "); DISPLAY(__VA_ARGS__); \ DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; } -static const U32 maxSrcLog = 24; -static const U32 maxSampleLog = 19; -int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibility) +static size_t FUZ_rLogLength(U32* seed, U32 logLength) { + size_t const lengthMask = ((size_t)1 << logLength) - 1; + return (lengthMask+1) + (FUZ_rand(seed) & lengthMask); +} + +static size_t FUZ_randomLength(U32* seed, U32 maxLog) +{ + U32 const logLength = FUZ_rand(seed) % maxLog; + return FUZ_rLogLength(seed, logLength); +} + +static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibility) +{ + static const U32 maxSrcLog = 24; + static const U32 maxSampleLog = 19; BYTE* cNoiseBuffer[5]; - BYTE* srcBuffer; size_t srcBufferSize = (size_t)1<= testNb) DISPLAYUPDATE(2, "/%6u ", nbTests); FUZ_rand(&coreSeed); lseed = coreSeed ^ prime1; - buffNb = FUZ_rand(&lseed) & 127; - if (buffNb & 7) buffNb=2; /* select buffer */ - else - { - buffNb >>= 3; - if (buffNb & 7) - { - const U32 tnb[2] = { 1, 3 }; - buffNb = tnb[buffNb >> 3]; - } - else - { - const U32 tnb[2] = { 0, 4 }; - buffNb = tnb[buffNb >> 3]; - } - } - srcBuffer = cNoiseBuffer[buffNb]; - /* Multi - segments compression test */ + /* state total reset */ + /* some problems only happen when states are re-used in a specific order */ + if ((FUZ_rand(&lseed) & 0xFF) == 131) { ZBUFF_freeCCtx(zc); zc = ZBUFF_createCCtx(); } + if ((FUZ_rand(&lseed) & 0xFF) == 132) { ZBUFF_freeDCtx(zd); zd = ZBUFF_createDCtx(); } + + /* srcBuffer selection [0-4] */ + { U32 buffNb = FUZ_rand(&lseed) & 0x7F; + if (buffNb & 7) buffNb=2; /* most common : compressible (P) */ + else { + buffNb >>= 3; + if (buffNb & 7) { + const U32 tnb[2] = { 1, 3 }; /* barely/highly compressible */ + buffNb = tnb[buffNb >> 3]; + } else { + const U32 tnb[2] = { 0, 4 }; /* not compressible / sparse */ + buffNb = tnb[buffNb >> 3]; + } } + srcBuffer = cNoiseBuffer[buffNb]; + } + + /* compression init */ + { U32 const testLog = FUZ_rand(&lseed) % maxSrcLog; + U32 const cLevel = (FUZ_rand(&lseed) % (ZSTD_maxCLevel() - (testLog/3))) + 1; + maxTestSize = FUZ_rLogLength(&lseed, testLog); + /* random dictionary selection */ + { size_t dictStart; + dictSize = (FUZ_rand(&lseed)==1) ? FUZ_randomLength(&lseed, maxSampleLog) : 0; + dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize); + dict = srcBuffer + dictStart; + } + { size_t const initError = ZBUFF_compressInitDictionary(zc, dict, dictSize, cLevel); + CHECK (ZBUFF_isError(initError),"init error : %s", ZBUFF_getErrorName(initError)); + } } + + /* multi-segments compression test */ XXH64_reset(xxh64, 0); - nbChunks = (FUZ_rand(&lseed) & 127) + 2; - sampleSizeLog = FUZ_rand(&lseed) % maxSrcLog; - maxTestSize = (size_t)1 << sampleSizeLog; - maxTestSize += FUZ_rand(&lseed) & (maxTestSize-1); + nbChunks = (FUZ_rand(&lseed) & 127) + 2; + for (n=0, cSize=0, totalTestSize=0 ; (n maxTestSize) break; + /* random flush operation, to mess around */ + if ((FUZ_rand(&lseed) & 15) == 0) { + size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog); + size_t dstBuffSize = MIN(cBufferSize - cSize, randomDstSize); + size_t const flushError = ZBUFF_compressFlush(zc, cBuffer+cSize, &dstBuffSize); + CHECK (ZBUFF_isError(flushError), "flush error : %s", ZBUFF_getErrorName(flushError)); + cSize += dstBuffSize; + } } + + /* final frame epilogue */ + { size_t dstBuffSize = cBufferSize - cSize; + size_t const flushError = ZBUFF_compressEnd(zc, cBuffer+cSize, &dstBuffSize); + CHECK (ZBUFF_isError(flushError), "flush error : %s", ZBUFF_getErrorName(flushError)); + cSize += dstBuffSize; } - genSize = cBufferSize - cSize; - errorCode = ZBUFF_compressEnd(zc, cBuffer+cSize, &genSize); - CHECK (ZBUFF_isError(errorCode), "compression error : %s", ZBUFF_getErrorName(errorCode)); - CHECK (errorCode != 0, "frame epilogue not fully consumed"); - cSize += genSize; crcOrig = XXH64_digest(xxh64); /* multi - fragments decompression test */ ZBUFF_decompressInitDictionary(zd, dict, dictSize); - totalCSize = 0; - totalGenSize = 0; - while (totalCSize < cSize) - { - sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog; - sampleSize = (size_t)1 << sampleSizeLog; - sampleSize += FUZ_rand(&lseed) & (sampleSize-1); - readSize = sampleSize; - sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog; - sampleSize = (size_t)1 << sampleSizeLog; - sampleSize += FUZ_rand(&lseed) & (sampleSize-1); - genSize = MIN(sampleSize, dstBufferSize - totalGenSize); - errorCode = ZBUFF_decompressContinue(zd, dstBuffer+totalGenSize, &genSize, cBuffer+totalCSize, &readSize); - CHECK (ZBUFF_isError(errorCode), "decompression error : %s", ZBUFF_getErrorName(errorCode)); - totalGenSize += genSize; - totalCSize += readSize; + for (totalCSize = 0, totalGenSize = 0 ; totalCSize < cSize ; ) { + size_t readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog); + size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog); + size_t dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize); + size_t const decompressError = ZBUFF_decompressContinue(zd, dstBuffer+totalGenSize, &dstBuffSize, cBuffer+totalCSize, &readCSrcSize); + CHECK (ZBUFF_isError(decompressError), "decompression error : %s", ZBUFF_getErrorName(decompressError)); + totalGenSize += dstBuffSize; + totalCSize += readCSrcSize; + errorCode = decompressError; /* needed for != 0 last test */ } CHECK (errorCode != 0, "frame not fully decoded"); CHECK (totalGenSize != totalTestSize, "decompressed data : wrong size") CHECK (totalCSize != cSize, "compressed data should be fully read") - crcDest = XXH64(dstBuffer, totalTestSize, 0); - if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize); - CHECK (crcDest!=crcOrig, "decompressed data corrupted"); + { U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0); + if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize); + CHECK (crcDest!=crcOrig, "decompressed data corrupted"); } + + /*===== noisy/erroneous src decompression test =====*/ - /* noisy/erroneous src decompression test */ /* add some noise */ - nbChunks = (FUZ_rand(&lseed) & 7) + 2; - for (n=0; n cSize/3) sampleSize = cSize/3; - sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize); - cStart = FUZ_rand(&lseed) % (cSize - sampleSize); - - memcpy(cBuffer+cStart, srcBuffer+sampleStart, sampleSize); - } + { U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2; + U32 nn; for (nn=0; nn='0') && (*argument<='9')) - { + while ((*argument>='0') && (*argument<='9')) { nbTests *= 10; nbTests += *argument - '0'; argument++; @@ -532,8 +503,7 @@ int main(int argc, char** argv) case 'T': argument++; nbTests=0; g_testTime=0; - while ((*argument>='0') && (*argument<='9')) - { + while ((*argument>='0') && (*argument<='9')) { g_testTime *= 10; g_testTime += *argument - '0'; argument++; @@ -547,8 +517,7 @@ int main(int argc, char** argv) argument++; seed=0; seedset=1; - while ((*argument>='0') && (*argument<='9')) - { + while ((*argument>='0') && (*argument<='9')) { seed *= 10; seed += *argument - '0'; argument++; @@ -558,8 +527,7 @@ int main(int argc, char** argv) case 't': argument++; testNb=0; - while ((*argument>='0') && (*argument<='9')) - { + while ((*argument>='0') && (*argument<='9')) { testNb *= 10; testNb += *argument - '0'; argument++; @@ -569,8 +537,7 @@ int main(int argc, char** argv) case 'P': /* compressibility % */ argument++; proba=0; - while ((*argument>='0') && (*argument<='9')) - { + while ((*argument>='0') && (*argument<='9')) { proba *= 10; proba += *argument - '0'; argument++; @@ -582,9 +549,7 @@ int main(int argc, char** argv) default: return FUZ_usage(programName); } - } - } - } + } } } /* for(argNb=1; argNb