From 2630a5eadc3cd7f591b747dfc95e3aba271695f0 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 14 Jan 2016 19:13:22 +0100 Subject: [PATCH 01/12] benchmark uses ZSTD_duplicateCCtx() --- programs/bench.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/programs/bench.c b/programs/bench.c index b80d6990bec..3c74a572ca4 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -224,6 +224,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, const size_t 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* dctx = ZSTD_createDCtx(); U64 crcOrig = XXH64(srcBuffer, srcSize, 0); @@ -233,7 +234,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, if (strlen(displayName)>17) displayName += strlen(displayName)-17; /* can only display 17 characters */ /* Memory allocation & restrictions */ - if (!compressedBuffer || !resultBuffer || !blockTable || !ctx || !dctx) + if (!compressedBuffer || !resultBuffer || !blockTable || !refCtx || !ctx || !dctx) EXM_THROW(31, "not enough memory"); /* Init blockTable data */ @@ -291,12 +292,27 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, milliTime = BMK_GetMilliStart(); while (BMK_GetMilliSpan(milliTime) < TIMELOOP) { + ZSTD_compressBegin_advanced(refCtx, ZSTD_getParams(cLevel, dictBufferSize+blockSize)); + ZSTD_compress_insertDictionary(refCtx, dictBuffer, dictBufferSize); for (blockNb=0; blockNb Date: Sun, 17 Jan 2016 00:12:55 +0100 Subject: [PATCH 02/12] small compression speed --- lib/zstd.h | 2 +- lib/zstd_compress.c | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/zstd.h b/lib/zstd.h index e201b5e0b9b..f7d364ad30d 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -62,7 +62,7 @@ extern "C" { ***************************************/ #define ZSTD_VERSION_MAJOR 0 /* for breaking interface changes */ #define ZSTD_VERSION_MINOR 4 /* for new (non-breaking) interface capabilities */ -#define ZSTD_VERSION_RELEASE 6 /* for tweaks, bug-fixes, or development */ +#define ZSTD_VERSION_RELEASE 7 /* for tweaks, bug-fixes, or development */ #define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) ZSTDLIB_API unsigned ZSTD_versionNumber (void); diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 399f8116962..19c64c11242 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1043,18 +1043,41 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co const U32 current = (U32)(ip-base); const U32 btLow = btMask >= current ? 0 : current - btMask; U32* smallerPtr = bt + 2*(current&btMask); - U32* largerPtr = bt + 2*(current&btMask) + 1; + U32* largerPtr = smallerPtr + 1; U32 dummy32; /* to be nullified at the end */ const U32 windowLow = zc->lowLimit; U32 matchEndIdx = current+8; + U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0) + 1; + U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1) + 1; hashTable[h] = current; /* Update Hash Table */ while (nbCompares-- && (matchIndex > windowLow)) { U32* nextPtr = bt + 2*(matchIndex & btMask); + const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ + if (matchIndex == predictedSmall) + { /* no need to check length, result known */ + *smallerPtr = matchIndex; + if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */ + smallerPtr = nextPtr+1; /* new "smaller" => larger of match */ + matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */ + predictedSmall = predictPtr[1] + 1; + continue; + } + + if (matchIndex == predictedLarge) + { + *largerPtr = matchIndex; + if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */ + largerPtr = nextPtr; + matchIndex = nextPtr[0]; + predictedLarge = predictPtr[0] + 1; + continue; + } + if ((!extDict) || (matchIndex+matchLength >= dictLimit)) { match = base + matchIndex; From fba6aed175676673d869d03c3bbf2e3c4f23c5ed Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 18 Jan 2016 12:03:27 +0100 Subject: [PATCH 03/12] changed : ZSTD_LEGACY_SUPPORT set to 0 by default within `zstd_decompress.c` (#113) --- lib/zstd.h | 2 +- lib/zstd_decompress.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/zstd.h b/lib/zstd.h index f7d364ad30d..695d26db973 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -44,7 +44,7 @@ extern "C" { /* *************************************************************** -* Tuning parameters +* Export parameters *****************************************************************/ /*! * ZSTD_DLL_EXPORT : diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index d11f6500960..cf68b1c132a 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -44,10 +44,10 @@ /*! * LEGACY_SUPPORT : -* ZSTD_decompress() can decode older formats (starting from zstd 0.1+) +* ZSTD_decompress() can decode older formats (v0.1+) if set to 1 */ #ifndef ZSTD_LEGACY_SUPPORT -# define ZSTD_LEGACY_SUPPORT 1 +# define ZSTD_LEGACY_SUPPORT 0 #endif From 1840d6af33478654358d540415625679c2d8fc0a Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 20 Jan 2016 15:39:06 +0100 Subject: [PATCH 04/12] bench pay attention to variable block sizes --- lib/zstd_static.h | 6 +++--- programs/bench.c | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/zstd_static.h b/lib/zstd_static.h index f1e72e955c4..a98cfead9bb 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -284,8 +284,8 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { /* W, C, H, S, L, strat */ { 0, 17, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */ { 0, 17, 12, 13, 1, 6, ZSTD_fast }, /* level 1 */ - { 0, 17, 15, 16, 1, 5, ZSTD_fast }, /* level 2 */ - { 0, 17, 16, 17, 1, 5, ZSTD_fast }, /* level 3 */ + { 0, 17, 14, 16, 1, 5, ZSTD_fast }, /* level 2 */ + { 0, 17, 15, 17, 1, 5, ZSTD_fast }, /* level 3 */ { 0, 17, 13, 15, 2, 4, ZSTD_greedy }, /* level 4 */ { 0, 17, 15, 17, 3, 4, ZSTD_greedy }, /* level 5 */ { 0, 17, 14, 17, 3, 4, ZSTD_lazy }, /* level 6 */ @@ -308,7 +308,7 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { /* W, C, H, S, L, strat */ { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */ { 0, 14, 14, 14, 1, 4, ZSTD_fast }, /* level 1 */ - { 0, 14, 14, 16, 1, 4, ZSTD_fast }, /* level 1 */ + { 0, 14, 14, 16, 1, 4, ZSTD_fast }, /* level 2 */ { 0, 14, 14, 14, 5, 4, ZSTD_greedy }, /* level 3 */ { 0, 14, 14, 14, 8, 4, ZSTD_greedy }, /* level 4 */ { 0, 14, 11, 14, 6, 4, ZSTD_lazy }, /* level 5 */ diff --git a/programs/bench.c b/programs/bench.c index 3c74a572ca4..14b36b489ff 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -220,6 +220,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, { 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 largestBlockSize = 0; 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 */ void* const compressedBuffer = malloc(maxCompressedSize); @@ -260,6 +261,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, cPtr += blockTable[nbBlocks].cRoom; resPtr += thisBlockSize; remaining -= thisBlockSize; + if (thisBlockSize > largestBlockSize) largestBlockSize = thisBlockSize; } } } @@ -292,7 +294,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, milliTime = BMK_GetMilliStart(); while (BMK_GetMilliSpan(milliTime) < TIMELOOP) { - ZSTD_compressBegin_advanced(refCtx, ZSTD_getParams(cLevel, dictBufferSize+blockSize)); + ZSTD_compressBegin_advanced(refCtx, ZSTD_getParams(cLevel, dictBufferSize+largestBlockSize)); ZSTD_compress_insertDictionary(refCtx, dictBuffer, dictBufferSize); for (blockNb=0; blockNb Date: Thu, 21 Jan 2016 02:21:17 +0100 Subject: [PATCH 05/12] bench : more accurate block nb in error report --- programs/bench.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/programs/bench.c b/programs/bench.c index 14b36b489ff..fcd674aac94 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -351,14 +351,21 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, crcCheck = XXH64(resultBuffer, srcSize, 0); if (crcOrig!=crcCheck) { - unsigned u; - unsigned eBlockSize = (unsigned)(MIN(65536*2, blockSize)); + 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[bn].srcSize; + } + printf("(block %u, pos %u) \n", bn, (U32)(u - bacc)); break; } } From 7beaa05d81a4186f72f885efad97484662a831f2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 21 Jan 2016 11:57:45 +0100 Subject: [PATCH 06/12] fixed bt bug --- lib/zstd_compress.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 19c64c11242..8487ec58f95 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1047,8 +1047,10 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co U32 dummy32; /* to be nullified at the end */ const U32 windowLow = zc->lowLimit; U32 matchEndIdx = current+8; - U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0) + 1; - U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1) + 1; + U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0); + U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1); + predictedSmall += (predictedSmall>0); + predictedLarge += (predictedLarge>0); hashTable[h] = current; /* Update Hash Table */ @@ -1064,7 +1066,7 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */ smallerPtr = nextPtr+1; /* new "smaller" => larger of match */ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */ - predictedSmall = predictPtr[1] + 1; + predictedSmall = predictPtr[1] + (predictPtr[1]>0); continue; } @@ -1074,7 +1076,7 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */ largerPtr = nextPtr; matchIndex = nextPtr[0]; - predictedLarge = predictPtr[0] + 1; + predictedLarge = predictPtr[0] + (predictPtr[0]>0); continue; } From 223f6337f8e64e69eecb55f4300d37a23ff7eda0 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 21 Jan 2016 13:33:05 +0100 Subject: [PATCH 07/12] updated NEWS --- NEWS | 5 +++++ images/CSpeed.png | Bin 36039 -> 35874 bytes images/DSpeed.png | Bin 9676 -> 9143 bytes 3 files changed, 5 insertions(+) diff --git a/NEWS b/NEWS index 9f3f8ce5025..8aaf02d99e4 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,8 @@ +v0.4.7 +Improved : small compression speed improvement in HC mode +Changed : `zstd_decompress.c` has ZSTD_LEGACY_SUPPORT to 0 by default +fix : bt search bug + v0.4.6 fix : fast compression mode on Windows New : cmake configuration file, thanks to Artyom Dymchenko diff --git a/images/CSpeed.png b/images/CSpeed.png index fe54752ef422bc5d0c098e5382a612ca2d18b907..5ba0561e6d7d0d6334878df83dbb7cacc8f1bcd5 100644 GIT binary patch literal 35874 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
w*G7S#Z!9 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%0DFV)n6 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 diff --git a/images/DSpeed.png b/images/DSpeed.png index 4db6437b0013451edd4b3fef2799468dbfa70bc1..1cd4713990acf5ad871d6156365d9ad69e203f3f 100644 GIT binary patch literal 9143 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 literal 9676 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 R{iBy-MkkLxJA5wme*l{xzNr8J From 74ce8e812c92d468e0a03abeb133fbf26eaaa869 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 21 Jan 2016 14:32:41 +0100 Subject: [PATCH 08/12] fixed VS 2015 'ERROR already defined', reported by Rich Geldreich --- lib/error.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/error.h b/lib/error.h index af3c1b5691d..2ec64d0c42c 100644 --- a/lib/error.h +++ b/lib/error.h @@ -64,6 +64,9 @@ extern "C" { ******************************************/ #define PREFIX(name) ZSTD_error_##name +#ifdef ERROR +# undef ERROR /* reported already defined on VS 2015 by Rich Geldreich */ +#endif #define ERROR(name) (size_t)-PREFIX(name) #define ERROR_LIST(ITEM) \ From 977f1f3600faf02a1f16d733848a0e1f87aeea76 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 21 Jan 2016 15:38:47 +0100 Subject: [PATCH 09/12] modified error system, following suggestions by @nemequ --- lib/bitstream.h | 4 +- lib/{error.h => error_private.h} | 63 ++++++++++++++++------------- lib/error_public.h | 69 ++++++++++++++++++++++++++++++++ lib/zstd_buffered.c | 5 ++- lib/zstd_internal.h | 2 +- lib/zstd_static.h | 2 +- programs/Makefile | 2 +- programs/fuzzer.c | 6 +-- 8 files changed, 116 insertions(+), 37 deletions(-) rename lib/{error.h => error_private.h} (58%) create mode 100644 lib/error_public.h diff --git a/lib/bitstream.h b/lib/bitstream.h index dcfe8b0a47a..fbd0f3f375f 100644 --- a/lib/bitstream.h +++ b/lib/bitstream.h @@ -50,8 +50,8 @@ extern "C" { /****************************************** * Includes ******************************************/ -#include "mem.h" /* unaligned access routines */ -#include "error.h" /* error codes and messages */ +#include "mem.h" /* unaligned access routines */ +#include "error_private.h" /* error codes and messages */ /******************************************** diff --git a/lib/error.h b/lib/error_private.h similarity index 58% rename from lib/error.h rename to lib/error_private.h index 2ec64d0c42c..dbb202f4553 100644 --- a/lib/error.h +++ b/lib/error_private.h @@ -1,6 +1,6 @@ /* ****************************************************************** Error codes and messages - Copyright (C) 2013-2015, Yann Collet + Copyright (C) 2013-2016, Yann Collet BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -28,9 +28,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - Source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c + - Source repository : https://github.com/Cyan4973/zstd ****************************************************************** */ +/* Note : this module is expected to remain private, do not expose it */ + #ifndef ERROR_H_MODULE #define ERROR_H_MODULE @@ -39,28 +40,29 @@ extern "C" { #endif -/****************************************** +/* ***************************************** * Includes ******************************************/ -#include /* size_t, ptrdiff_t */ +#include /* size_t, ptrdiff_t */ +#include "error_public.h" /* enum list */ -/****************************************** +/* ***************************************** * Compiler-specific ******************************************/ -#if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +#if defined(__GNUC__) +# define ERR_STATIC static __attribute__((unused)) +#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) # define ERR_STATIC static inline #elif defined(_MSC_VER) # define ERR_STATIC static __inline -#elif defined(__GNUC__) -# define ERR_STATIC static __attribute__((unused)) #else # define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ #endif -/****************************************** -* Error Management +/* ***************************************** +* Error Codes ******************************************/ #define PREFIX(name) ZSTD_error_##name @@ -69,29 +71,34 @@ extern "C" { #endif #define ERROR(name) (size_t)-PREFIX(name) -#define ERROR_LIST(ITEM) \ - ITEM(PREFIX(No_Error)) ITEM(PREFIX(GENERIC)) \ - ITEM(PREFIX(prefix_unknown)) ITEM(PREFIX(frameParameter_unsupported)) ITEM(PREFIX(frameParameter_unsupportedBy32bitsImplementation)) \ - ITEM(PREFIX(init_missing)) ITEM(PREFIX(memory_allocation)) ITEM(PREFIX(stage_wrong)) \ - ITEM(PREFIX(dstSize_tooSmall)) ITEM(PREFIX(srcSize_wrong)) \ - ITEM(PREFIX(corruption_detected)) \ - ITEM(PREFIX(tableLog_tooLarge)) ITEM(PREFIX(maxSymbolValue_tooLarge)) ITEM(PREFIX(maxSymbolValue_tooSmall)) \ - ITEM(PREFIX(maxCode)) - -#define ERROR_GENERATE_ENUM(ENUM) ENUM, -typedef enum { ERROR_LIST(ERROR_GENERATE_ENUM) } ERR_codes; /* enum is exposed, to detect & handle specific errors; compare function result to -enum value */ +ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } -#define ERROR_CONVERTTOSTRING(STRING) #STRING, -#define ERROR_GENERATE_STRING(EXPR) ERROR_CONVERTTOSTRING(EXPR) -static const char* ERR_strings[] = { ERROR_LIST(ERROR_GENERATE_STRING) }; -ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } +/* ***************************************** +* Error Strings +******************************************/ ERR_STATIC const char* ERR_getErrorName(size_t code) { static const char* codeError = "Unspecified error code"; - if (ERR_isError(code)) return ERR_strings[-(int)(code)]; - return codeError; + switch( (size_t)-code ) + { + case ZSTD_error_No_Error: return "No error detected"; + case ZSTD_error_GENERIC: return "Error (generic)"; + case ZSTD_error_prefix_unknown: return "Unknown frame descriptor"; + case ZSTD_error_frameParameter_unsupported: return "Unsupported frame parameter"; + case ZSTD_error_frameParameter_unsupportedBy32bitsImplementation: return "Frame parameter unsupported in 32-bits mode"; + case ZSTD_error_init_missing: return "Context should be init first"; + case ZSTD_error_memory_allocation: return "Allocation error : not enough memory"; + case ZSTD_error_dstSize_tooSmall: return "Destination buffer is too small"; + case ZSTD_error_srcSize_wrong: return "Src size incorrect"; + case ZSTD_error_corruption_detected: return "Corrupted block detected"; + case ZSTD_error_tableLog_tooLarge: return "tableLog requires too much memory"; + case ZSTD_error_maxSymbolValue_tooLarge: return "Unsupported max possible Symbol Value : too large"; + case ZSTD_error_maxSymbolValue_tooSmall: return "Specified maxSymbolValue is too small"; + case ZSTD_error_maxCode: + default: return codeError; + } } diff --git a/lib/error_public.h b/lib/error_public.h new file mode 100644 index 00000000000..a07d00cebd0 --- /dev/null +++ b/lib/error_public.h @@ -0,0 +1,69 @@ +/* ****************************************************************** + Error codes list + Copyright (C) 2016, Yann Collet + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - Source repository : https://github.com/Cyan4973/zstd +****************************************************************** */ +#ifndef ERROR_PUBLIC_H_MODULE +#define ERROR_PUBLIC_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif + + +/* **************************************** +* error list +******************************************/ +enum { + ZSTD_error_No_Error, + ZSTD_error_GENERIC, + ZSTD_error_prefix_unknown, + ZSTD_error_frameParameter_unsupported, + ZSTD_error_frameParameter_unsupportedBy32bitsImplementation, + ZSTD_error_init_missing, + ZSTD_error_memory_allocation, + ZSTD_error_stage_wrong, + ZSTD_error_dstSize_tooSmall, + ZSTD_error_srcSize_wrong, + ZSTD_error_corruption_detected, + ZSTD_error_tableLog_tooLarge, + ZSTD_error_maxSymbolValue_tooLarge, + ZSTD_error_maxSymbolValue_tooSmall, + ZSTD_error_maxCode +}; + +/* note : functions provide error codes are provided as (size_t)-enum */ + + +#if defined (__cplusplus) +} +#endif + +#endif /* ERROR_PUBLIC_H_MODULE */ diff --git a/lib/zstd_buffered.c b/lib/zstd_buffered.c index 8a7fa1d1110..48721d62802 100644 --- a/lib/zstd_buffered.c +++ b/lib/zstd_buffered.c @@ -39,7 +39,7 @@ * Includes ***************************************/ #include -#include "error.h" +#include "error_private.h" #include "zstd_static.h" #include "zstd_buffered_static.h" @@ -243,6 +243,8 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc, zbc->stage = ZBUFFcs_load; break; } + default: + return ERROR(GENERIC); /* impossible */ } } @@ -534,6 +536,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt notDone = 0; break; } + default: return ERROR(GENERIC); /* impossible */ } } diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index bddfc929354..cae2cb8f897 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -41,7 +41,7 @@ extern "C" { * Includes ***************************************/ #include "mem.h" -#include "error.h" +#include "error_private.h" /* ************************************* diff --git a/lib/zstd_static.h b/lib/zstd_static.h index a98cfead9bb..c60fa65c223 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -334,7 +334,7 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { /* ************************************* * Error management ***************************************/ -#include "error.h" +#include "error_public.h" #if defined (__cplusplus) diff --git a/programs/Makefile b/programs/Makefile index 182f91a3898..c64cbe6b93a 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -45,7 +45,7 @@ DESTDIR?= PREFIX ?= /usr/local CPPFLAGS= -I../lib -DZSTD_VERSION=\"$(VERSION)\" CFLAGS ?= -O3 # -falign-loops=32 # not always beneficial -CFLAGS += -std=c99 -Wall -Wextra -Wundef -Wshadow -Wcast-qual -Wcast-align -Wstrict-prototypes -Wstrict-aliasing=1 +CFLAGS += -std=c99 -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wstrict-aliasing=1 -Wswitch-enum -Wstrict-prototypes -Wundef FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(MOREFLAGS) BINDIR = $(PREFIX)/bin diff --git a/programs/fuzzer.c b/programs/fuzzer.c index 9c427c20639..4058ef24d69 100644 --- a/programs/fuzzer.c +++ b/programs/fuzzer.c @@ -185,13 +185,13 @@ static int basicUnitTests(U32 seed, double compressibility) DISPLAYLEVEL(4, "test%3i : decompress with 1 missing byte : ", testNb++); result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize-1); if (!ZSTD_isError(result)) goto _output_error; - if (result != ERROR(srcSize_wrong)) goto _output_error; + if (result != (size_t)-ZSTD_error_srcSize_wrong) goto _output_error; DISPLAYLEVEL(4, "OK \n"); DISPLAYLEVEL(4, "test%3i : decompress with 1 too much byte : ", testNb++); result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize+1); if (!ZSTD_isError(result)) goto _output_error; - if (result != ERROR(srcSize_wrong)) goto _output_error; + if (result != (size_t)-ZSTD_error_srcSize_wrong) goto _output_error; DISPLAYLEVEL(4, "OK \n"); /* Dictionary and Duplication tests */ @@ -259,7 +259,7 @@ static int basicUnitTests(U32 seed, double compressibility) DISPLAYLEVEL(4, "test%3i : Check input length for magic number : ", testNb++); result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, CNBuffer, 3); if (!ZSTD_isError(result)) goto _output_error; - if (result != ERROR(srcSize_wrong)) goto _output_error; + if (result != (size_t)-ZSTD_error_srcSize_wrong) goto _output_error; DISPLAYLEVEL(4, "OK \n"); DISPLAYLEVEL(4, "test%3i : Check magic Number : ", testNb++); From ffec740d37c696f76555f564bae130f9989175d1 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 21 Jan 2016 15:50:11 +0100 Subject: [PATCH 10/12] fixed visual and clang errors --- lib/legacy/zstd_legacy.h | 6 +++--- lib/legacy/zstd_v01.c | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/legacy/zstd_legacy.h b/lib/legacy/zstd_legacy.h index 308d1342f94..b3e5eb2047b 100644 --- a/lib/legacy/zstd_legacy.h +++ b/lib/legacy/zstd_legacy.h @@ -40,8 +40,8 @@ extern "C" { /* ************************************* * Includes ***************************************/ -#include "mem.h" /* MEM_STATIC */ -#include "error.h" /* ERROR */ +#include "mem.h" /* MEM_STATIC */ +#include "error_private.h" /* ERROR */ #include "zstd_v01.h" #include "zstd_v02.h" #include "zstd_v03.h" @@ -51,7 +51,7 @@ MEM_STATIC unsigned ZSTD_isLegacy (U32 magicNumberLE) switch(magicNumberLE) { case ZSTDv01_magicNumberLE : - case ZSTDv02_magicNumber : + case ZSTDv02_magicNumber : case ZSTDv03_magicNumber : return 1; default : return 0; } diff --git a/lib/legacy/zstd_v01.c b/lib/legacy/zstd_v01.c index 7a8486b58ba..2fcf188851b 100644 --- a/lib/legacy/zstd_v01.c +++ b/lib/legacy/zstd_v01.c @@ -1630,6 +1630,7 @@ static size_t ZSTD_decodeLiteralsBlock(void* ctx, ip += litcSize; break; } + case bt_end: default: return (size_t)-ZSTD_ERROR_GENERIC; } From a768a301ba23eea5c7389c0cddd4bc15645b1865 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 21 Jan 2016 16:04:35 +0100 Subject: [PATCH 11/12] fixed VS project --- lib/error_private.h | 2 +- lib/error_public.h | 3 +- lib/zstd_compress.c | 1 - lib/zstd_decompress.c | 2 +- visual/2013/zstdlib/zstdlib.vcxproj | 1 - visual/2013/zstdlib/zstdlib.vcxproj.filters | 155 ++++++++++---------- 6 files changed, 80 insertions(+), 84 deletions(-) diff --git a/lib/error_private.h b/lib/error_private.h index dbb202f4553..e56753899dc 100644 --- a/lib/error_private.h +++ b/lib/error_private.h @@ -81,7 +81,7 @@ ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } ERR_STATIC const char* ERR_getErrorName(size_t code) { static const char* codeError = "Unspecified error code"; - switch( (size_t)-code ) + switch( (size_t)(0-code) ) { case ZSTD_error_No_Error: return "No error detected"; case ZSTD_error_GENERIC: return "Error (generic)"; diff --git a/lib/error_public.h b/lib/error_public.h index a07d00cebd0..78b0e80a909 100644 --- a/lib/error_public.h +++ b/lib/error_public.h @@ -59,7 +59,8 @@ enum { ZSTD_error_maxCode }; -/* note : functions provide error codes are provided as (size_t)-enum */ +/* note : functions provide error codes in reverse negative order, + so compare with (size_t)(0-enum) */ #if defined (__cplusplus) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 8487ec58f95..d01807bd35f 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -39,7 +39,6 @@ # define FORCE_INLINE static __forceinline # include /* For Visual 2005 */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -# pragma warning(disable : 4324) /* disable: C4324: padded structure */ #else # define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) # ifdef __GNUC__ diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index cf68b1c132a..4a026df33d6 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -799,7 +799,7 @@ size_t ZSTD_decompress(void* dst, size_t maxDstSize, const void* src, size_t src #else ZSTD_DCtx dctx; return ZSTD_decompressDCtx(&dctx, dst, maxDstSize, src, srcSize); -#endif // defined +#endif } diff --git a/visual/2013/zstdlib/zstdlib.vcxproj b/visual/2013/zstdlib/zstdlib.vcxproj index 124595556a0..a580048b68e 100644 --- a/visual/2013/zstdlib/zstdlib.vcxproj +++ b/visual/2013/zstdlib/zstdlib.vcxproj @@ -27,7 +27,6 @@ - diff --git a/visual/2013/zstdlib/zstdlib.vcxproj.filters b/visual/2013/zstdlib/zstdlib.vcxproj.filters index 9e930d7b1e2..8600c5f4f1d 100644 --- a/visual/2013/zstdlib/zstdlib.vcxproj.filters +++ b/visual/2013/zstdlib/zstdlib.vcxproj.filters @@ -1,80 +1,77 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file From dd283b1f4f71fb39df6588fd97ebb952241b4f49 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 21 Jan 2016 16:08:01 +0100 Subject: [PATCH 12/12] fixed cmake --- contrib/cmake/lib/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/cmake/lib/CMakeLists.txt b/contrib/cmake/lib/CMakeLists.txt index f15244275b3..a8247ddca70 100644 --- a/contrib/cmake/lib/CMakeLists.txt +++ b/contrib/cmake/lib/CMakeLists.txt @@ -66,7 +66,8 @@ SET(Sources SET(Headers ${LIBRARY_DIR}/bitstream.h - ${LIBRARY_DIR}/error.h + ${LIBRARY_DIR}/error_private.h + ${LIBRARY_DIR}/error_public.h ${LIBRARY_DIR}/fse.h ${LIBRARY_DIR}/fse_static.h ${LIBRARY_DIR}/huff0.h