summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYann Collet <cyan@fb.com>2018-04-27 19:59:20 (GMT)
committerYann Collet <cyan@fb.com>2018-04-27 19:59:20 (GMT)
commitde7b274d996ee16f22cfdb94f2564788939e0af0 (patch)
tree25705defae8cc961483bea5ae2719657848a60c5
parent19b1267d44a6bd3fbb1b682d515a3ab5dc70ec50 (diff)
parent47d70e755e67d187da43ffe14d5ce47bf1ff04de (diff)
downloadlz4-de7b274d996ee16f22cfdb94f2564788939e0af0.zip
lz4-de7b274d996ee16f22cfdb94f2564788939e0af0.tar.gz
lz4-de7b274d996ee16f22cfdb94f2564788939e0af0.tar.bz2
Merge branch 'dev' into BD_deterministic
-rw-r--r--doc/lz4_manual.html12
-rw-r--r--doc/lz4frame_manual.html63
-rw-r--r--examples/frameCompress.c3
-rw-r--r--lib/lz4.c6
-rw-r--r--lib/lz4frame.c3
-rw-r--r--lib/lz4frame.h9
-rw-r--r--lib/lz4hc.c70
-rw-r--r--lib/lz4hc.h18
-rw-r--r--programs/lz4cli.c2
-rw-r--r--programs/lz4io.c8
-rw-r--r--programs/lz4io.h7
11 files changed, 152 insertions, 49 deletions
diff --git a/doc/lz4_manual.html b/doc/lz4_manual.html
index f8639fe..ddd2724 100644
--- a/doc/lz4_manual.html
+++ b/doc/lz4_manual.html
@@ -126,15 +126,17 @@ int LZ4_compress_fast_extState (void* state, const char* src, char* dst, int src
<pre><b>int LZ4_decompress_fast (const char* src, char* dst, int originalSize);
</b><p>This function is a bit faster than LZ4_decompress_safe(),
-but doesn't provide any security guarantee.
+but it may misbehave on malformed input because it doesn't perform full validation of compressed data.
originalSize : is the uncompressed size to regenerate
Destination buffer must be already allocated, and its size must be >= 'originalSize' bytes.
return : number of bytes read from source buffer (== compressed size).
If the source stream is detected malformed, the function stops decoding and return a negative result.
- note : This function respects memory boundaries for *properly formed* compressed data.
- However, it does not provide any protection against malicious input.
- It also doesn't know 'src' size, and implies it's >= compressed size.
- Use this function in trusted environment **only**.
+ note : This function is only usable if the originalSize of uncompressed data is known in advance.
+ The caller should also check that all the compressed input has been consumed properly,
+ i.e. that the return value matches the size of the buffer with compressed input.
+ The function never writes past the output buffer. However, since it doesn't know its 'src' size,
+ it may read past the intended input. Also, because match offsets are not validated during decoding,
+ reads from 'src' may underflow. Use this function in trusted environment **only**.
</p></pre><BR>
<pre><b>int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity);
diff --git a/doc/lz4frame_manual.html b/doc/lz4frame_manual.html
index 459bac8..53ea7eb 100644
--- a/doc/lz4frame_manual.html
+++ b/doc/lz4frame_manual.html
@@ -18,6 +18,7 @@
<li><a href="#Chapter8">Compression</a></li>
<li><a href="#Chapter9">Decompression functions</a></li>
<li><a href="#Chapter10">Streaming decompression functions</a></li>
+<li><a href="#Chapter11">Bulk processing dictionary API</a></li>
</ol>
<hr>
<a name="Chapter1"></a><h2>Introduction</h2><pre>
@@ -89,12 +90,13 @@
<pre><b>typedef struct {
LZ4F_frameInfo_t frameInfo;
- int compressionLevel; </b>/* 0: default (fast mode); values > LZ4HC_CLEVEL_MAX count as LZ4HC_CLEVEL_MAX; values < 0 trigger "fast acceleration" */<b>
- unsigned autoFlush; </b>/* 1 == always flush, to reduce usage of internal buffers */<b>
- unsigned reserved[4]; </b>/* must be zero for forward compatibility */<b>
+ int compressionLevel; </b>/* 0: default (fast mode); values > LZ4HC_CLEVEL_MAX count as LZ4HC_CLEVEL_MAX; values < 0 trigger "fast acceleration" */<b>
+ unsigned autoFlush; </b>/* 1: always flush, to reduce usage of internal buffers */<b>
+ unsigned favorDecSpeed; </b>/* 1: parser favors decompression speed vs compression ratio. Only works for high compression modes (>= LZ4LZ4HC_CLEVEL_OPT_MIN) */ /* >= v1.8.2 */<b>
+ unsigned reserved[3]; </b>/* must be zero for forward compatibility */<b>
} LZ4F_preferences_t;
</b><p> makes it possible to supply detailed compression parameters to the stream interface.
- It's not required to set all fields, as long as the structure was initially memset() to zero.
+ Structure is presumed initially memset() to zero, representing default settings.
All reserved fields must be set to zero.
</p></pre><BR>
@@ -293,5 +295,58 @@ LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx);
and start a new one using same context resources.
</p></pre><BR>
+<pre><b>typedef enum { LZ4F_LIST_ERRORS(LZ4F_GENERATE_ENUM) } LZ4F_errorCodes;
+</b></pre><BR>
+<a name="Chapter11"></a><h2>Bulk processing dictionary API</h2><pre></pre>
+
+<pre><b>LZ4FLIB_STATIC_API LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize);
+LZ4FLIB_STATIC_API void LZ4F_freeCDict(LZ4F_CDict* CDict);
+</b><p> When compressing multiple messages / blocks with the same dictionary, it's recommended to load it just once.
+ LZ4_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay.
+ LZ4_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only.
+ `dictBuffer` can be released after LZ4_CDict creation, since its content is copied within CDict
+</p></pre><BR>
+
+<pre><b>LZ4FLIB_STATIC_API size_t LZ4F_compressFrame_usingCDict(
+ LZ4F_cctx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const LZ4F_CDict* cdict,
+ const LZ4F_preferences_t* preferencesPtr);
+</b><p> Compress an entire srcBuffer into a valid LZ4 frame using a digested Dictionary.
+ cctx must point to a context created by LZ4F_createCompressionContext().
+ If cdict==NULL, compress without a dictionary.
+ dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr).
+ If this condition is not respected, function will fail (@return an errorCode).
+ The LZ4F_preferences_t structure is optional : you may provide NULL as argument,
+ but it's not recommended, as it's the only way to provide dictID in the frame header.
+ @return : number of bytes written into dstBuffer.
+ or an error code if it fails (can be tested using LZ4F_isError())
+</p></pre><BR>
+
+<pre><b>LZ4FLIB_STATIC_API size_t LZ4F_compressBegin_usingCDict(
+ LZ4F_cctx* cctx,
+ void* dstBuffer, size_t dstCapacity,
+ const LZ4F_CDict* cdict,
+ const LZ4F_preferences_t* prefsPtr);
+</b><p> Inits streaming dictionary compression, and writes the frame header into dstBuffer.
+ dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes.
+ `prefsPtr` is optional : you may provide NULL as argument,
+ however, it's the only way to provide dictID in the frame header.
+ @return : number of bytes written into dstBuffer for the header,
+ or an error code (which can be tested using LZ4F_isError())
+</p></pre><BR>
+
+<pre><b>LZ4FLIB_STATIC_API size_t LZ4F_decompress_usingDict(
+ LZ4F_dctx* dctxPtr,
+ void* dstBuffer, size_t* dstSizePtr,
+ const void* srcBuffer, size_t* srcSizePtr,
+ const void* dict, size_t dictSize,
+ const LZ4F_decompressOptions_t* decompressOptionsPtr);
+</b><p> Same as LZ4F_decompress(), using a predefined dictionary.
+ Dictionary is used "in place", without any preprocessing.
+ It must remain accessible throughout the entire frame decoding.
+</p></pre><BR>
+
</html>
</body>
diff --git a/examples/frameCompress.c b/examples/frameCompress.c
index 972f716..9bfea48 100644
--- a/examples/frameCompress.c
+++ b/examples/frameCompress.c
@@ -21,7 +21,8 @@ static const LZ4F_preferences_t kPrefs = {
0 /* unknown content size */, 0 /* no dictID */ , LZ4F_noBlockChecksum },
0, /* compression level; 0 == default */
0, /* autoflush */
- { 0, 0, 0, 0 }, /* reserved, must be set to 0 */
+ 0, /* favor decompression speed */
+ { 0, 0, 0 }, /* reserved, must be set to 0 */
};
diff --git a/lib/lz4.c b/lib/lz4.c
index b4d3140..06ff611 100644
--- a/lib/lz4.c
+++ b/lib/lz4.c
@@ -161,11 +161,11 @@
* Memory routines
**************************************/
#include <stdlib.h> /* malloc, calloc, free */
-#define ALLOC(s) malloc(s)
+#define ALLOC(s) malloc(s)
#define ALLOC_AND_ZERO(s) calloc(1,s)
-#define FREEMEM free
+#define FREEMEM(p) free(p)
#include <string.h> /* memset, memcpy */
-#define MEM_INIT memset
+#define MEM_INIT(p,v,s) memset((p),(v),(s))
/*-************************************
diff --git a/lib/lz4frame.c b/lib/lz4frame.c
index 4d6d39c..93ce696 100644
--- a/lib/lz4frame.c
+++ b/lib/lz4frame.c
@@ -612,6 +612,9 @@ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr,
/* frame init only for blockLinked : blockIndependent will be init at each block */
LZ4F_applyCDict(cctxPtr->lz4CtxPtr, cdict, cctxPtr->prefs.compressionLevel);
}
+ if (preferencesPtr->compressionLevel >= LZ4HC_CLEVEL_MIN) {
+ LZ4_favorDecompressionSpeed((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, (int)preferencesPtr->favorDecSpeed);
+ }
/* Magic Number */
LZ4F_writeLE32(dstPtr, LZ4F_MAGICNUMBER);
diff --git a/lib/lz4frame.h b/lib/lz4frame.h
index bd715bd..fb434ff 100644
--- a/lib/lz4frame.h
+++ b/lib/lz4frame.h
@@ -173,13 +173,14 @@ typedef struct {
/*! LZ4F_preferences_t :
* makes it possible to supply detailed compression parameters to the stream interface.
- * It's not required to set all fields, as long as the structure was initially memset() to zero.
+ * Structure is presumed initially memset() to zero, representing default settings.
* All reserved fields must be set to zero. */
typedef struct {
LZ4F_frameInfo_t frameInfo;
- int compressionLevel; /* 0: default (fast mode); values > LZ4HC_CLEVEL_MAX count as LZ4HC_CLEVEL_MAX; values < 0 trigger "fast acceleration" */
- unsigned autoFlush; /* 1 == always flush, to reduce usage of internal buffers */
- unsigned reserved[4]; /* must be zero for forward compatibility */
+ int compressionLevel; /* 0: default (fast mode); values > LZ4HC_CLEVEL_MAX count as LZ4HC_CLEVEL_MAX; values < 0 trigger "fast acceleration" */
+ unsigned autoFlush; /* 1: always flush, to reduce usage of internal buffers */
+ unsigned favorDecSpeed; /* 1: parser favors decompression speed vs compression ratio. Only works for high compression modes (>= LZ4LZ4HC_CLEVEL_OPT_MIN) */ /* >= v1.8.2 */
+ unsigned reserved[3]; /* must be zero for forward compatibility */
} LZ4F_preferences_t;
LZ4FLIB_API int LZ4F_compressionLevel_max(void);
diff --git a/lib/lz4hc.c b/lib/lz4hc.c
index 184ca8c..f2dc21b 100644
--- a/lib/lz4hc.c
+++ b/lib/lz4hc.c
@@ -200,6 +200,7 @@ LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)
}
typedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;
+typedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;
LZ4_FORCE_INLINE int
LZ4HC_InsertAndGetWiderMatch (
@@ -212,7 +213,8 @@ LZ4HC_InsertAndGetWiderMatch (
const BYTE** startpos,
const int maxNbAttempts,
const int patternAnalysis,
- const dictCtx_directive dict)
+ const dictCtx_directive dict,
+ const HCfavor_e favorDecSpeed)
{
U16* const chainTable = hc4->chainTable;
U32* const HashTable = hc4->hashTable;
@@ -241,7 +243,10 @@ LZ4HC_InsertAndGetWiderMatch (
while ((matchIndex>=lowLimit) && (nbAttempts)) {
DEBUGLOG(7, "remaining attempts : %i", nbAttempts);
nbAttempts--;
- if (matchIndex >= dictLimit) {
+ assert(matchIndex < ipIndex);
+ if (favorDecSpeed && (ipIndex - matchIndex < 8)) {
+ /* do nothing */
+ } else if (matchIndex >= dictLimit) {
const BYTE* const matchPtr = base + matchIndex;
assert(matchPtr >= lowPrefixPtr);
assert(matchPtr < ip);
@@ -328,14 +333,12 @@ LZ4HC_InsertAndGetWiderMatch (
}
}
- {
- U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);
+ { U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);
dictMatchIndex -= nextOffset;
matchIndex -= nextOffset;
}
}
}
-
return longest;
}
@@ -351,7 +354,7 @@ int LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index tabl
/* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
* but this won't be the case here, as we define iLowLimit==ip,
* so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
- return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, matchpos, &uselessPtr, maxNbAttempts, patternAnalysis, dict);
+ return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, matchpos, &uselessPtr, maxNbAttempts, patternAnalysis, dict, favorCompressionRatio);
}
@@ -484,7 +487,7 @@ _Search2:
if (ip+ml <= mflimit) {
ml2 = LZ4HC_InsertAndGetWiderMatch(ctx,
ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2,
- maxNbAttempts, patternAnalysis, dict);
+ maxNbAttempts, patternAnalysis, dict, favorCompressionRatio);
} else {
ml2 = ml;
}
@@ -529,7 +532,7 @@ _Search3:
if (start2 + ml2 <= mflimit) {
ml3 = LZ4HC_InsertAndGetWiderMatch(ctx,
start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3,
- maxNbAttempts, patternAnalysis, dict);
+ maxNbAttempts, patternAnalysis, dict, favorCompressionRatio);
} else {
ml3 = ml2;
}
@@ -650,12 +653,14 @@ _dest_overflow:
return 0;
}
+
static int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx,
const char* const source, char* dst,
int* srcSizePtr, int dstCapacity,
int const nbSearches, size_t sufficient_len,
const limitedOutput_directive limit, int const fullUpdate,
- const dictCtx_directive dict);
+ const dictCtx_directive dict,
+ HCfavor_e favorDecSpeed);
LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (
@@ -700,6 +705,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (
if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT; /* note : convention is different from lz4frame, maybe something to review */
cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);
{ cParams_t const cParam = clTable[cLevel];
+ HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;
if (cParam.strat == lz4hc)
return LZ4HC_compress_hashChain(ctx,
src, dst, srcSizePtr, dstCapacity,
@@ -708,7 +714,8 @@ LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (
return LZ4HC_compress_optimal(ctx,
src, dst, srcSizePtr, dstCapacity,
cParam.nbSearches, cParam.targetLength, limit,
- cLevel == LZ4HC_CLEVEL_MAX, dict); /* ultra mode */
+ cLevel == LZ4HC_CLEVEL_MAX, /* ultra mode */
+ dict, favor);
}
}
@@ -746,7 +753,7 @@ static int LZ4HC_compress_generic_dictCtx (
} else if (position == 0 && *srcSizePtr > 4 KB) {
memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));
LZ4HC_setExternalDict(ctx, (const BYTE *)src);
- ctx->compressionLevel = cLevel;
+ ctx->compressionLevel = (short)cLevel;
return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
} else {
return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtx);
@@ -795,7 +802,7 @@ int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int src
int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
{
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
- LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t));
+ LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
#else
LZ4_streamHC_t state;
LZ4_streamHC_t* const statePtr = &state;
@@ -824,10 +831,9 @@ int LZ4_compress_HC_destSize(void* LZ4HC_Data, const char* source, char* dest, i
**************************************/
/* allocation */
LZ4_streamHC_t* LZ4_createStreamHC(void) {
- LZ4_streamHC_t* LZ4_streamHCPtr = (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t));
- LZ4_streamHCPtr->internal_donotuse.end = (const BYTE *)(ptrdiff_t)-1;
- LZ4_streamHCPtr->internal_donotuse.base = NULL;
- LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL;
+ LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
+ if (LZ4_streamHCPtr==NULL) return NULL;
+ LZ4_resetStreamHC(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT);
return LZ4_streamHCPtr;
}
@@ -847,6 +853,7 @@ void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
LZ4_streamHCPtr->internal_donotuse.end = (const BYTE *)(ptrdiff_t)-1;
LZ4_streamHCPtr->internal_donotuse.base = NULL;
LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL;
+ LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = 0;
LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
}
@@ -863,7 +870,12 @@ void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLev
{
if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT;
if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX;
- LZ4_streamHCPtr->internal_donotuse.compressionLevel = compressionLevel;
+ LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel;
+}
+
+void LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor)
+{
+ LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0);
}
int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize)
@@ -1080,23 +1092,26 @@ LZ4_FORCE_INLINE LZ4HC_match_t
LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,
const BYTE* ip, const BYTE* const iHighLimit,
int minLen, int nbSearches,
- const dictCtx_directive dict)
+ const dictCtx_directive dict,
+ const HCfavor_e favorDecSpeed)
{
LZ4HC_match_t match = { 0 , 0 };
const BYTE* matchPtr = NULL;
/* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
* but this won't be the case here, as we define iLowLimit==ip,
* so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
- int const matchLength = LZ4HC_InsertAndGetWiderMatch(ctx,
+ int matchLength = LZ4HC_InsertAndGetWiderMatch(ctx,
ip, ip, iHighLimit, minLen, &matchPtr, &ip,
- nbSearches, 1 /* patternAnalysis */, dict);
+ nbSearches, 1 /* patternAnalysis */, dict, favorDecSpeed);
if (matchLength <= minLen) return match;
+ if (favorDecSpeed) {
+ if ((matchLength>18) & (matchLength<=36)) matchLength=18; /* favor shortcut */
+ }
match.len = matchLength;
match.off = (int)(ip-matchPtr);
return match;
}
-
static int LZ4HC_compress_optimal (
LZ4HC_CCtx_internal* ctx,
const char* const source,
@@ -1107,7 +1122,8 @@ static int LZ4HC_compress_optimal (
size_t sufficient_len,
const limitedOutput_directive limit,
int const fullUpdate,
- const dictCtx_directive dict
+ const dictCtx_directive dict,
+ const HCfavor_e favorDecSpeed
)
{
#define TRAILING_LITERALS 3
@@ -1135,7 +1151,7 @@ static int LZ4HC_compress_optimal (
int best_mlen, best_off;
int cur, last_match_pos = 0;
- LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict);
+ LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);
if (firstMatch.len==0) { ip++; continue; }
if ((size_t)firstMatch.len > sufficient_len) {
@@ -1205,10 +1221,10 @@ static int LZ4HC_compress_optimal (
DEBUGLOG(7, "search at rPos:%u", cur);
if (fullUpdate)
- newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict);
+ newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);
else
/* only test matches of minimum length; slightly faster, but misses a few bytes */
- newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict);
+ newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict, favorDecSpeed);
if (!newMatch.len) continue;
if ( ((size_t)newMatch.len > sufficient_len)
@@ -1256,7 +1272,9 @@ static int LZ4HC_compress_optimal (
price = opt[cur].price + LZ4HC_sequencePrice(0, ml);
}
- if (pos > last_match_pos+TRAILING_LITERALS || price <= opt[pos].price) {
+ assert((U32)favorDecSpeed <= 1);
+ if (pos > last_match_pos+TRAILING_LITERALS
+ || price <= opt[pos].price - (int)favorDecSpeed) {
DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i)",
pos, price, ml);
assert(pos < LZ4_OPT_NUM);
diff --git a/lib/lz4hc.h b/lib/lz4hc.h
index 28e2528..bb5e073 100644
--- a/lib/lz4hc.h
+++ b/lib/lz4hc.h
@@ -152,7 +152,8 @@ struct LZ4HC_CCtx_internal
uint32_t dictLimit; /* below that point, need extDict */
uint32_t lowLimit; /* below that point, no more dict */
uint32_t nextToUpdate; /* index from which to continue dictionary update */
- int compressionLevel;
+ short compressionLevel;
+ short favorDecSpeed;
const LZ4HC_CCtx_internal* dictCtx;
};
@@ -169,7 +170,8 @@ struct LZ4HC_CCtx_internal
unsigned int dictLimit; /* below that point, need extDict */
unsigned int lowLimit; /* below that point, no more dict */
unsigned int nextToUpdate; /* index from which to continue dictionary update */
- int compressionLevel;
+ short compressionLevel;
+ short favorDecSpeed;
const LZ4HC_CCtx_internal* dictCtx;
};
@@ -253,9 +255,9 @@ LZ4_DEPRECATED("use LZ4_resetStreamHC() instead") LZ4LIB_API int LZ4_resetStr
* `srcSizePtr` : value will be updated to indicate how much bytes were read from `src`
*/
int LZ4_compress_HC_destSize(void* LZ4HC_Data,
- const char* src, char* dst,
- int* srcSizePtr, int targetDstSize,
- int compressionLevel);
+ const char* src, char* dst,
+ int* srcSizePtr, int targetDstSize,
+ int compressionLevel);
/*! LZ4_compress_HC_continue_destSize() : v1.8.0 (experimental)
* Similar as LZ4_compress_HC_continue(),
@@ -275,6 +277,12 @@ int LZ4_compress_HC_continue_destSize(LZ4_streamHC_t* LZ4_streamHCPtr,
*/
void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel);
+/*! LZ4_favorDecompressionSpeed() : v1.8.2 (experimental)
+ * Parser will select decisions favoring decompression over compression ratio.
+ * Only work at highest compression settings (level >= LZ4HC_CLEVEL_OPT_MIN)
+ */
+void LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor);
+
/*! LZ4_resetStreamHC_fast() :
* When an LZ4_streamHC_t is known to be in a internally coherent state,
* it can often be prepared for a new compression with almost no work, only
diff --git a/programs/lz4cli.c b/programs/lz4cli.c
index 42392eb..ba519b4 100644
--- a/programs/lz4cli.c
+++ b/programs/lz4cli.c
@@ -140,6 +140,7 @@ static int usage_advanced(const char* exeName)
DISPLAY( "--no-frame-crc : disable stream checksum (default:enabled) \n");
DISPLAY( "--content-size : compressed frame includes original size (default:not present)\n");
DISPLAY( "--[no-]sparse : sparse mode (default:enabled on file, disabled on stdout)\n");
+ DISPLAY( "--favor-decSpeed: compressed files decompress faster, but are less compressed \n");
DISPLAY( "Benchmark arguments : \n");
DISPLAY( " -b# : benchmark file(s), using # compression level (default : 1) \n");
DISPLAY( " -e# : test all compression levels from -bX to # (default : 1)\n");
@@ -355,6 +356,7 @@ int main(int argc, const char** argv)
if (!strcmp(argument, "--no-content-size")) { LZ4IO_setContentSize(0); continue; }
if (!strcmp(argument, "--sparse")) { LZ4IO_setSparseFile(2); continue; }
if (!strcmp(argument, "--no-sparse")) { LZ4IO_setSparseFile(0); continue; }
+ if (!strcmp(argument, "--favor-decSpeed")) { LZ4IO_favorDecSpeed(1); continue; }
if (!strcmp(argument, "--verbose")) { displayLevel++; continue; }
if (!strcmp(argument, "--quiet")) { if (displayLevel) displayLevel--; continue; }
if (!strcmp(argument, "--version")) { DISPLAY(WELCOME_MESSAGE); return 0; }
diff --git a/programs/lz4io.c b/programs/lz4io.c
index ccf4fa1..b52c1f3 100644
--- a/programs/lz4io.c
+++ b/programs/lz4io.c
@@ -116,6 +116,7 @@ static int g_blockIndependence = 1;
static int g_sparseFileSupport = 1;
static int g_contentSizeFlag = 0;
static int g_useDictionary = 0;
+static unsigned g_favorDecSpeed = 0;
static const char* g_dictionaryFilename = NULL;
@@ -221,6 +222,12 @@ int LZ4IO_setContentSize(int enable)
return g_contentSizeFlag;
}
+/* Default setting : 0 (disabled) */
+void LZ4IO_favorDecSpeed(int favor)
+{
+ g_favorDecSpeed = (favor!=0);
+}
+
static U32 g_removeSrcFile = 0;
void LZ4IO_setRemoveSrcFile(unsigned flag) { g_removeSrcFile = (flag>0); }
@@ -548,6 +555,7 @@ static int LZ4IO_compressFilename_extRess(cRess_t ress, const char* srcFileName,
prefs.frameInfo.blockSizeID = (LZ4F_blockSizeID_t)g_blockSizeId;
prefs.frameInfo.blockChecksumFlag = (LZ4F_blockChecksum_t)g_blockChecksum;
prefs.frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)g_streamChecksum;
+ prefs.favorDecSpeed = g_favorDecSpeed;
if (g_contentSizeFlag) {
U64 const fileSize = UTIL_getFileSize(srcFileName);
prefs.frameInfo.contentSize = fileSize; /* == 0 if input == stdin */
diff --git a/programs/lz4io.h b/programs/lz4io.h
index b21b8b6..22c5e3e 100644
--- a/programs/lz4io.h
+++ b/programs/lz4io.h
@@ -94,10 +94,15 @@ int LZ4IO_setNotificationLevel(int level);
/* Default setting : 0 (disabled) */
int LZ4IO_setSparseFile(int enable);
-/* Default setting : 0 (disabled) */
+/* Default setting : 0 == no content size present in frame header */
int LZ4IO_setContentSize(int enable);
+/* Default setting : 0 == src file preserved */
void LZ4IO_setRemoveSrcFile(unsigned flag);
+/* Default setting : 0 == favor compression ratio
+ * Note : 1 only works for high compression levels (10+) */
+void LZ4IO_favorDecSpeed(int favor);
+
#endif /* LZ4IO_H_237902873 */