updated to latest LZ4 source

This commit is contained in:
iceman1001 2020-09-28 10:47:13 +02:00
commit 74050af8c2
4 changed files with 1525 additions and 1410 deletions

File diff suppressed because it is too large Load diff

View file

@ -186,7 +186,8 @@ LZ4LIB_API int LZ4_compressBound(int inputSize);
The larger the acceleration value, the faster the algorithm, but also the lesser the compression. The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.
An acceleration value of "1" is the same as regular LZ4_compress_default() An acceleration value of "1" is the same as regular LZ4_compress_default()
Values <= 0 will be replaced by ACCELERATION_DEFAULT (currently == 1, see lz4.c). Values <= 0 will be replaced by LZ4_ACCELERATION_DEFAULT (currently == 1, see lz4.c).
Values > LZ4_ACCELERATION_MAX will be replaced by LZ4_ACCELERATION_MAX (currently == 65537, see lz4.c).
*/ */
LZ4LIB_API int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); LZ4LIB_API int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
@ -212,6 +213,17 @@ LZ4LIB_API int LZ4_compress_fast_extState(void *state, const char *src, char *ds
* New value is necessarily <= input value. * New value is necessarily <= input value.
* @return : Nb bytes written into 'dst' (necessarily <= targetDestSize) * @return : Nb bytes written into 'dst' (necessarily <= targetDestSize)
* or 0 if compression fails. * or 0 if compression fails.
*
* Note : from v1.8.2 to v1.9.1, this function had a bug (fixed un v1.9.2+):
* the produced compressed content could, in specific circumstances,
* require to be decompressed into a destination buffer larger
* by at least 1 byte than the content to decompress.
* If an application uses `LZ4_compress_destSize()`,
* it's highly recommended to update liblz4 to v1.9.2 or better.
* If this can't be done or ensured,
* the receiving decompression function should provide
* a dstCapacity which is > decompressedSize, by at least 1 byte.
* See https://github.com/lz4/lz4/issues/859 for details
*/ */
LZ4LIB_API int LZ4_compress_destSize (const char* src, char* dst, int* srcSizePtr, int targetDstSize); LZ4LIB_API int LZ4_compress_destSize (const char* src, char* dst, int* srcSizePtr, int targetDstSize);
@ -220,25 +232,35 @@ LZ4LIB_API int LZ4_compress_destSize(const char *src, char *dst, int *srcSizePtr
* Decompress an LZ4 compressed block, of size 'srcSize' at position 'src', * Decompress an LZ4 compressed block, of size 'srcSize' at position 'src',
* into destination buffer 'dst' of size 'dstCapacity'. * into destination buffer 'dst' of size 'dstCapacity'.
* Up to 'targetOutputSize' bytes will be decoded. * Up to 'targetOutputSize' bytes will be decoded.
* The function stops decoding on reaching this objective, * The function stops decoding on reaching this objective.
* which can boost performance when only the beginning of a block is required. * This can be useful to boost performance
* whenever only the beginning of a block is required.
* *
* @return : the number of bytes decoded in `dst` (necessarily <= dstCapacity) * @return : the number of bytes decoded in `dst` (necessarily <= targetOutputSize)
* If source stream is detected malformed, function returns a negative result. * If source stream is detected malformed, function returns a negative result.
* *
* Note : @return can be < targetOutputSize, if compressed block contains less data. * Note 1 : @return can be < targetOutputSize, if compressed block contains less data.
* *
* Note 2 : this function features 2 parameters, targetOutputSize and dstCapacity, * Note 2 : targetOutputSize must be <= dstCapacity
* and expects targetOutputSize <= dstCapacity. *
* It effectively stops decoding on reaching targetOutputSize, * Note 3 : this function effectively stops decoding on reaching targetOutputSize,
* so dstCapacity is kind of redundant. * so dstCapacity is kind of redundant.
* This is because in a previous version of this function, * This is because in older versions of this function,
* decoding operation would not "break" a sequence in the middle. * decoding operation would still write complete sequences.
* As a consequence, there was no guarantee that decoding would stop at exactly targetOutputSize, * Therefore, there was no guarantee that it would stop writing at exactly targetOutputSize,
* it could write more bytes, though only up to dstCapacity. * it could write more bytes, though only up to dstCapacity.
* Some "margin" used to be required for this operation to work properly. * Some "margin" used to be required for this operation to work properly.
* This is no longer necessary. * Thankfully, this is no longer necessary.
* The function nonetheless keeps its signature, in an effort to not break API. * The function nonetheless keeps the same signature, in an effort to preserve API compatibility.
*
* Note 4 : If srcSize is the exact size of the block,
* then targetOutputSize can be any value,
* including larger than the block's decompressed size.
* The function will, at most, generate block's decompressed size.
*
* Note 5 : If srcSize is _larger_ than block's compressed size,
* then targetOutputSize **MUST** be <= block's decompressed size.
* Otherwise, *silent corruption will occur*.
*/ */
LZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity); LZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity);
@ -564,8 +586,7 @@ typedef struct LZ4_stream_t_internal LZ4_stream_t_internal;
struct LZ4_stream_t_internal { struct LZ4_stream_t_internal {
uint32_t hashTable[LZ4_HASH_SIZE_U32]; uint32_t hashTable[LZ4_HASH_SIZE_U32];
uint32_t currentOffset; uint32_t currentOffset;
uint16_t dirty; uint32_t tableType;
uint16_t tableType;
const uint8_t* dictionary; const uint8_t* dictionary;
const LZ4_stream_t_internal* dictCtx; const LZ4_stream_t_internal* dictCtx;
uint32_t dictSize; uint32_t dictSize;
@ -584,8 +605,7 @@ typedef struct LZ4_stream_t_internal LZ4_stream_t_internal;
struct LZ4_stream_t_internal { struct LZ4_stream_t_internal {
unsigned int hashTable[LZ4_HASH_SIZE_U32]; unsigned int hashTable[LZ4_HASH_SIZE_U32];
unsigned int currentOffset; unsigned int currentOffset;
unsigned short dirty; unsigned int tableType;
unsigned short tableType;
const unsigned char* dictionary; const unsigned char* dictionary;
const LZ4_stream_t_internal* dictCtx; const LZ4_stream_t_internal* dictCtx;
unsigned int dictSize; unsigned int dictSize;
@ -667,18 +687,17 @@ union LZ4_streamDecode_u {
#ifdef LZ4_DISABLE_DEPRECATE_WARNINGS #ifdef LZ4_DISABLE_DEPRECATE_WARNINGS
# define LZ4_DEPRECATED(message) /* disable deprecation warnings */ # define LZ4_DEPRECATED(message) /* disable deprecation warnings */
#else #else
# define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ # if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */
# define LZ4_DEPRECATED(message) [[deprecated(message)]] # define LZ4_DEPRECATED(message) [[deprecated(message)]]
# elif (LZ4_GCC_VERSION >= 405) || defined(__clang__)
# define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))
# elif (LZ4_GCC_VERSION >= 301)
# define LZ4_DEPRECATED(message) __attribute__((deprecated))
# elif defined(_MSC_VER) # elif defined(_MSC_VER)
# define LZ4_DEPRECATED(message) __declspec(deprecated(message)) # define LZ4_DEPRECATED(message) __declspec(deprecated(message))
# elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 45))
# define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))
# elif defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 31)
# define LZ4_DEPRECATED(message) __attribute__((deprecated))
# else # else
# pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler") # pragma message("WARNING: LZ4_DEPRECATED needs custom implementation for this compiler")
# define LZ4_DEPRECATED(message) # define LZ4_DEPRECATED(message) /* disabled */
# endif # endif
#endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */ #endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */

View file

@ -90,12 +90,14 @@ static U32 LZ4HC_hashPtr(const void *ptr) { return HASH_FUNCTION(LZ4_read32(ptr)
/************************************** /**************************************
* HC Compression * HC Compression
**************************************/ **************************************/
static void LZ4HC_clearTables(LZ4HC_CCtx_internal *hc4) { static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)
{
MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable)); MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable));
MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable)); MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
} }
static void LZ4HC_init_internal(LZ4HC_CCtx_internal *hc4, const BYTE *start) { static void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start)
{
uptrval startingOffset = (uptrval)(hc4->end - hc4->base); uptrval startingOffset = (uptrval)(hc4->end - hc4->base);
if (startingOffset > 1 GB) { if (startingOffset > 1 GB) {
LZ4HC_clearTables(hc4); LZ4HC_clearTables(hc4);
@ -112,7 +114,8 @@ static void LZ4HC_init_internal(LZ4HC_CCtx_internal *hc4, const BYTE *start) {
/* Update chains up to ip (excluded) */ /* Update chains up to ip (excluded) */
LZ4_FORCE_INLINE void LZ4HC_Insert(LZ4HC_CCtx_internal *hc4, const BYTE *ip) { LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
{
U16* const chainTable = hc4->chainTable; U16* const chainTable = hc4->chainTable;
U32* const hashTable = hc4->hashTable; U32* const hashTable = hc4->hashTable;
const BYTE* const base = hc4->base; const BYTE* const base = hc4->base;
@ -135,14 +138,13 @@ LZ4_FORCE_INLINE void LZ4HC_Insert(LZ4HC_CCtx_internal *hc4, const BYTE *ip) {
* @return : negative value, nb of common bytes before ip/match */ * @return : negative value, nb of common bytes before ip/match */
LZ4_FORCE_INLINE LZ4_FORCE_INLINE
int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match, int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,
const BYTE *const iMin, const BYTE *const mMin) { const BYTE* const iMin, const BYTE* const mMin)
{
int back = 0; int back = 0;
int const min = (int)MAX(iMin - ip, mMin - match); int const min = (int)MAX(iMin - ip, mMin - match);
assert(min <= 0); assert(min <= 0);
assert(ip >= iMin); assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));
assert((size_t)(ip - iMin) < (1U << 31)); assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));
assert(match >= mMin);
assert((size_t)(match - mMin) < (1U << 31));
while ( (back > min) while ( (back > min)
&& (ip[back-1] == match[back-1]) ) && (ip[back-1] == match[back-1]) )
back--; back--;
@ -156,7 +158,8 @@ int LZ4HC_countBack(const BYTE *const ip, const BYTE *const match,
#endif #endif
static U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern) { static U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern)
{
size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3; size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3;
if (bitsToRotate == 0) if (bitsToRotate == 0)
return pattern; return pattern;
@ -166,7 +169,8 @@ static U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern) {
/* LZ4HC_countPattern() : /* LZ4HC_countPattern() :
* pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */ * pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */
static unsigned static unsigned
LZ4HC_countPattern(const BYTE *ip, const BYTE *const iEnd, U32 const pattern32) { LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32)
{
const BYTE* const iStart = ip; const BYTE* const iStart = ip;
reg_t const pattern = (sizeof(pattern)==8) ? (reg_t)pattern32 + (((reg_t)pattern32) << 32) : pattern32; reg_t const pattern = (sizeof(pattern)==8) ? (reg_t)pattern32 + (((reg_t)pattern32) << 32) : pattern32;
@ -180,16 +184,14 @@ LZ4HC_countPattern(const BYTE *ip, const BYTE *const iEnd, U32 const pattern32)
if (LZ4_isLittleEndian()) { if (LZ4_isLittleEndian()) {
reg_t patternByte = pattern; reg_t patternByte = pattern;
while ((ip<iEnd) && (*ip == (BYTE)patternByte)) { while ((ip<iEnd) && (*ip == (BYTE)patternByte)) {
ip++; ip++; patternByte >>= 8;
patternByte >>= 8;
} }
} else { /* big endian */ } else { /* big endian */
U32 bitOffset = (sizeof(pattern)*8) - 8; U32 bitOffset = (sizeof(pattern)*8) - 8;
while (ip < iEnd) { while (ip < iEnd) {
BYTE const byte = (BYTE)(pattern >> bitOffset); BYTE const byte = (BYTE)(pattern >> bitOffset);
if (*ip != byte) break; if (*ip != byte) break;
ip ++; ip ++; bitOffset -= 8;
bitOffset -= 8;
} }
} }
@ -200,21 +202,19 @@ LZ4HC_countPattern(const BYTE *ip, const BYTE *const iEnd, U32 const pattern32)
* pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) * pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)
* read using natural platform endianess */ * read using natural platform endianess */
static unsigned static unsigned
LZ4HC_reverseCountPattern(const BYTE *ip, const BYTE *const iLow, U32 pattern) { LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)
{
const BYTE* const iStart = ip; const BYTE* const iStart = ip;
while (likely(ip >= iLow+4)) { while (likely(ip >= iLow+4)) {
if (LZ4_read32(ip-4) != pattern) break; if (LZ4_read32(ip-4) != pattern) break;
ip -= 4; ip -= 4;
} }
{ { const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianess */
const BYTE *bytePtr = (const BYTE *)(&pattern) + 3; /* works for any endianess */
while (likely(ip>iLow)) { while (likely(ip>iLow)) {
if (ip[-1] != *bytePtr) break; if (ip[-1] != *bytePtr) break;
ip--; ip--; bytePtr--;
bytePtr--; } }
}
}
return (unsigned)(iStart - ip); return (unsigned)(iStart - ip);
} }
@ -223,7 +223,8 @@ LZ4HC_reverseCountPattern(const BYTE *ip, const BYTE *const iLow, U32 pattern) {
* 4 byte MINMATCH would overflow. * 4 byte MINMATCH would overflow.
* @returns true if the match index is okay. * @returns true if the match index is okay.
*/ */
static int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex) { static int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex)
{
return ((U32)((dictLimit - 1) - matchIndex) >= 3); return ((U32)((dictLimit - 1) - matchIndex) >= 3);
} }
@ -243,7 +244,8 @@ LZ4HC_InsertAndGetWiderMatch(
const int patternAnalysis, const int patternAnalysis,
const int chainSwap, const int chainSwap,
const dictCtx_directive dict, const dictCtx_directive dict,
const HCfavor_e favorDecSpeed) { const HCfavor_e favorDecSpeed)
{
U16* const chainTable = hc4->chainTable; U16* const chainTable = hc4->chainTable;
U32* const HashTable = hc4->hashTable; U32* const HashTable = hc4->hashTable;
const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx; const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx;
@ -288,9 +290,7 @@ LZ4HC_InsertAndGetWiderMatch(
longest = matchLength; longest = matchLength;
*matchpos = matchPtr + back; *matchpos = matchPtr + back;
*startpos = ip + back; *startpos = ip + back;
} } } }
}
}
} else { /* lowestMatchIndex <= matchIndex < dictLimit */ } else { /* lowestMatchIndex <= matchIndex < dictLimit */
const BYTE* const matchPtr = dictBase + matchIndex; const BYTE* const matchPtr = dictBase + matchIndex;
if (LZ4_read32(matchPtr) == pattern) { if (LZ4_read32(matchPtr) == pattern) {
@ -307,9 +307,7 @@ LZ4HC_InsertAndGetWiderMatch(
longest = matchLength; longest = matchLength;
*matchpos = base + matchIndex + back; /* virtual pos, relative to ip, to retrieve offset */ *matchpos = base + matchIndex + back; /* virtual pos, relative to ip, to retrieve offset */
*startpos = ip + back; *startpos = ip + back;
} } } }
}
}
if (chainSwap && matchLength==longest) { /* better match => select a better chain */ if (chainSwap && matchLength==longest) { /* better match => select a better chain */
assert(lookBackLength==0); /* search forward only */ assert(lookBackLength==0); /* search forward only */
@ -333,12 +331,9 @@ LZ4HC_InsertAndGetWiderMatch(
if (distanceToNextMatch > matchIndex) break; /* avoid overflow */ if (distanceToNextMatch > matchIndex) break; /* avoid overflow */
matchIndex -= distanceToNextMatch; matchIndex -= distanceToNextMatch;
continue; continue;
} } } }
}
}
{ { U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex);
U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex);
if (patternAnalysis && distNextMatch==1 && matchChainPos==0) { if (patternAnalysis && distNextMatch==1 && matchChainPos==0) {
U32 const matchCandidateIdx = matchIndex-1; U32 const matchCandidateIdx = matchIndex-1;
/* may be a repeated pattern */ /* may be a repeated pattern */
@ -349,8 +344,7 @@ LZ4HC_InsertAndGetWiderMatch(
srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern); srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);
} else { } else {
repeat = rep_not; repeat = rep_not;
} } }
}
if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex) if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)
&& LZ4HC_protectDictEnd(dictLimit, matchCandidateIdx) ) { && LZ4HC_protectDictEnd(dictLimit, matchCandidateIdx) ) {
const int extDict = matchCandidateIdx < dictLimit; const int extDict = matchCandidateIdx < dictLimit;
@ -363,8 +357,7 @@ LZ4HC_InsertAndGetWiderMatch(
U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern); U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern);
forwardPatternLength += LZ4HC_countPattern(lowPrefixPtr, iHighLimit, rotatedPattern); forwardPatternLength += LZ4HC_countPattern(lowPrefixPtr, iHighLimit, rotatedPattern);
} }
{ { const BYTE* const lowestMatchPtr = extDict ? dictStart : lowPrefixPtr;
const BYTE *const lowestMatchPtr = extDict ? dictStart : lowPrefixPtr;
size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern); size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);
size_t currentSegmentLength; size_t currentSegmentLength;
if (!extDict && matchPtr - backLength == lowPrefixPtr && hc4->lowLimit < dictLimit) { if (!extDict && matchPtr - backLength == lowPrefixPtr && hc4->lowLimit < dictLimit) {
@ -396,27 +389,20 @@ LZ4HC_InsertAndGetWiderMatch(
if (lookBackLength==0) { /* no back possible */ if (lookBackLength==0) { /* no back possible */
size_t const maxML = MIN(currentSegmentLength, srcPatternLength); size_t const maxML = MIN(currentSegmentLength, srcPatternLength);
if ((size_t)longest < maxML) { if ((size_t)longest < maxML) {
assert(base + matchIndex < ip); assert(base + matchIndex != ip);
if (ip - (base + matchIndex) > LZ4_DISTANCE_MAX) break; if ((size_t)(ip - base) - matchIndex > LZ4_DISTANCE_MAX) break;
assert(maxML < 2 GB); assert(maxML < 2 GB);
longest = (int)maxML; longest = (int)maxML;
*matchpos = base + matchIndex; /* virtual pos, relative to ip, to retrieve offset */ *matchpos = base + matchIndex; /* virtual pos, relative to ip, to retrieve offset */
*startpos = ip; *startpos = ip;
} }
{ { U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);
U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);
if (distToNextPattern > matchIndex) break; /* avoid overflow */ if (distToNextPattern > matchIndex) break; /* avoid overflow */
matchIndex -= distToNextPattern; matchIndex -= distToNextPattern;
} } } } } }
}
}
}
}
continue; continue;
} } }
} } } /* PA optimization */
}
} /* PA optimization */
/* follow current chain */ /* follow current chain */
matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos); matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos);
@ -445,16 +431,12 @@ LZ4HC_InsertAndGetWiderMatch(
longest = mlt; longest = mlt;
*matchpos = base + matchIndex + back; *matchpos = base + matchIndex + back;
*startpos = ip + back; *startpos = ip + back;
} } }
}
{ { U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);
U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);
dictMatchIndex -= nextOffset; dictMatchIndex -= nextOffset;
matchIndex -= nextOffset; matchIndex -= nextOffset;
} } } }
}
}
return longest; return longest;
} }
@ -465,7 +447,8 @@ int LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal *const hc4, /* Index tabl
const BYTE** matchpos, const BYTE** matchpos,
const int maxNbAttempts, const int maxNbAttempts,
const int patternAnalysis, const int patternAnalysis,
const dictCtx_directive dict) { const dictCtx_directive dict)
{
const BYTE* uselessPtr = ip; const BYTE* uselessPtr = ip;
/* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos), /* 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, * but this won't be the case here, as we define iLowLimit==ip,
@ -483,7 +466,8 @@ LZ4_FORCE_INLINE int LZ4HC_encodeSequence(
int matchLength, int matchLength,
const BYTE* const match, const BYTE* const match,
limitedOutput_directive limit, limitedOutput_directive limit,
BYTE *oend) { BYTE* oend)
{
size_t length; size_t length;
BYTE* const token = (*op)++; BYTE* const token = (*op)++;
@ -522,8 +506,7 @@ LZ4_FORCE_INLINE int LZ4HC_encodeSequence(
/* Encode Offset */ /* Encode Offset */
assert( (*ip - match) <= LZ4_DISTANCE_MAX ); /* note : consider providing offset as a value, rather than as a pointer difference */ assert( (*ip - match) <= LZ4_DISTANCE_MAX ); /* note : consider providing offset as a value, rather than as a pointer difference */
LZ4_writeLE16(*op, (U16)(*ip - match)); LZ4_writeLE16(*op, (U16)(*ip-match)); *op += 2;
*op += 2;
/* Encode MatchLength */ /* Encode MatchLength */
assert(matchLength >= MINMATCH); assert(matchLength >= MINMATCH);
@ -555,7 +538,8 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain(
unsigned maxNbAttempts, unsigned maxNbAttempts,
const limitedOutput_directive limit, const limitedOutput_directive limit,
const dictCtx_directive dict const dictCtx_directive dict
) { )
{
const int inputSize = *srcSizePtr; const int inputSize = *srcSizePtr;
const int patternAnalysis = (maxNbAttempts > 128); /* levels 9+ */ const int patternAnalysis = (maxNbAttempts > 128); /* levels 9+ */
@ -589,9 +573,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain(
if (ml<MINMATCH) { ip++; continue; } if (ml<MINMATCH) { ip++; continue; }
/* saved, in case we would skip too much */ /* saved, in case we would skip too much */
start0 = ip; start0 = ip; ref0 = ref; ml0 = ml;
ref0 = ref;
ml0 = ml;
_Search2: _Search2:
if (ip+ml <= mflimit) { if (ip+ml <= mflimit) {
@ -610,11 +592,8 @@ _Search2:
if (start0 < ip) { /* first match was skipped at least once */ if (start0 < ip) { /* first match was skipped at least once */
if (start2 < ip + ml0) { /* squeezing ML1 between ML0(original ML1) and ML2 */ if (start2 < ip + ml0) { /* squeezing ML1 between ML0(original ML1) and ML2 */
ip = start0; ip = start0; ref = ref0; ml = ml0; /* restore initial ML1 */
ref = ref0; } }
ml = ml0; /* restore initial ML1 */
}
}
/* Here, start0==ip */ /* Here, start0==ip */
if ((start2 - ip) < 3) { /* First Match too small : removed */ if ((start2 - ip) < 3) { /* First Match too small : removed */
@ -718,14 +697,10 @@ _Search3:
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow; if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
/* ML2 becomes ML1 */ /* ML2 becomes ML1 */
ip = start2; ip = start2; ref = ref2; ml = ml2;
ref = ref2;
ml = ml2;
/* ML3 becomes ML2 */ /* ML3 becomes ML2 */
start2 = start3; start2 = start3; ref2 = ref3; ml2 = ml3;
ref2 = ref3;
ml2 = ml3;
/* let's find a new ML3 */ /* let's find a new ML3 */
goto _Search3; goto _Search3;
@ -733,8 +708,7 @@ _Search3:
_last_literals: _last_literals:
/* Encode Last Literals */ /* Encode Last Literals */
{ { size_t lastRunSize = (size_t)(iend - anchor); /* literals */
size_t lastRunSize = (size_t)(iend - anchor); /* literals */
size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255; size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255;
size_t const totalSize = 1 + litLength + lastRunSize; size_t const totalSize = 1 + litLength + lastRunSize;
if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */ if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */
@ -790,7 +764,8 @@ LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal(
int cLevel, int cLevel,
const limitedOutput_directive limit, const limitedOutput_directive limit,
const dictCtx_directive dict const dictCtx_directive dict
) { )
{
typedef enum { lz4hc, lz4opt } lz4hc_strat_e; typedef enum { lz4hc, lz4opt } lz4hc_strat_e;
typedef struct { typedef struct {
lz4hc_strat_e strat; lz4hc_strat_e strat;
@ -821,8 +796,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal(
ctx->end += *srcSizePtr; ctx->end += *srcSizePtr;
if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT; /* note : convention is different from lz4frame, maybe something to review */ if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT; /* note : convention is different from lz4frame, maybe something to review */
cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel); cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);
{ { cParams_t const cParam = clTable[cLevel];
cParams_t const cParam = clTable[cLevel];
HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio; HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;
int result; int result;
@ -854,7 +828,8 @@ LZ4HC_compress_generic_noDictCtx(
int const dstCapacity, int const dstCapacity,
int cLevel, int cLevel,
limitedOutput_directive limit limitedOutput_directive limit
) { )
{
assert(ctx->dictCtx == NULL); assert(ctx->dictCtx == NULL);
return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx); return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx);
} }
@ -868,7 +843,8 @@ LZ4HC_compress_generic_dictCtx(
int const dstCapacity, int const dstCapacity,
int cLevel, int cLevel,
limitedOutput_directive limit limitedOutput_directive limit
) { )
{
const size_t position = (size_t)(ctx->end - ctx->base) - ctx->lowLimit; const size_t position = (size_t)(ctx->end - ctx->base) - ctx->lowLimit;
assert(ctx->dictCtx != NULL); assert(ctx->dictCtx != NULL);
if (position >= 64 KB) { if (position >= 64 KB) {
@ -893,7 +869,8 @@ LZ4HC_compress_generic(
int const dstCapacity, int const dstCapacity,
int cLevel, int cLevel,
limitedOutput_directive limit limitedOutput_directive limit
) { )
{
if (ctx->dictCtx == NULL) { if (ctx->dictCtx == NULL) {
return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit); return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
} else { } else {
@ -907,15 +884,17 @@ int LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); }
#ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 : #ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 :
* it reports an aligment of 8-bytes, * it reports an aligment of 8-bytes,
* while actually aligning LZ4_streamHC_t on 4 bytes. */ * while actually aligning LZ4_streamHC_t on 4 bytes. */
static size_t LZ4_streamHC_t_alignment(void) { static size_t LZ4_streamHC_t_alignment(void)
struct { char c; LZ4_streamHC_t t; } t_a; {
return sizeof(t_a) - sizeof(t_a.t); typedef struct { char c; LZ4_streamHC_t t; } t_a;
return sizeof(t_a) - sizeof(LZ4_streamHC_t);
} }
#endif #endif
/* state is presumed correctly initialized, /* state is presumed correctly initialized,
* in which case its size and alignment have already been validate */ * in which case its size and alignment have already been validate */
int LZ4_compress_HC_extStateHC_fastReset(void *state, const char *src, char *dst, int srcSize, int dstCapacity, int compressionLevel) { int LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
{
LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse; LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;
#ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 : #ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 :
* it reports an aligment of 8-bytes, * it reports an aligment of 8-bytes,
@ -931,13 +910,15 @@ int LZ4_compress_HC_extStateHC_fastReset(void *state, const char *src, char *dst
return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited); return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited);
} }
int LZ4_compress_HC_extStateHC(void *state, const char *src, char *dst, int srcSize, int dstCapacity, int compressionLevel) { int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
{
LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx)); LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
if (ctx==NULL) return 0; /* init failure */ if (ctx==NULL) return 0; /* init failure */
return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel); return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel);
} }
int LZ4_compress_HC(const char *src, char *dst, int srcSize, int dstCapacity, int compressionLevel) { int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
{
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t)); LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
#else #else
@ -952,7 +933,8 @@ int LZ4_compress_HC(const char *src, char *dst, int srcSize, int dstCapacity, in
} }
/* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */ /* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */
int LZ4_compress_HC_destSize(void *state, const char *source, char *dest, int *sourceSizePtr, int targetDestSize, int cLevel) { int LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)
{
LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx)); LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
if (ctx==NULL) return 0; /* init failure */ if (ctx==NULL) return 0; /* init failure */
LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source); LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source);
@ -966,14 +948,16 @@ int LZ4_compress_HC_destSize(void *state, const char *source, char *dest, int *s
* Streaming Functions * Streaming Functions
**************************************/ **************************************/
/* allocation */ /* allocation */
LZ4_streamHC_t *LZ4_createStreamHC(void) { LZ4_streamHC_t* LZ4_createStreamHC(void)
{
LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t)); LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
if (LZ4_streamHCPtr==NULL) return NULL; if (LZ4_streamHCPtr==NULL) return NULL;
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); /* full initialization, malloc'ed buffer can be full of garbage */ LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); /* full initialization, malloc'ed buffer can be full of garbage */
return LZ4_streamHCPtr; return LZ4_streamHCPtr;
} }
int LZ4_freeStreamHC(LZ4_streamHC_t *LZ4_streamHCPtr) { int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)
{
DEBUGLOG(4, "LZ4_freeStreamHC(%p)", LZ4_streamHCPtr); DEBUGLOG(4, "LZ4_freeStreamHC(%p)", LZ4_streamHCPtr);
if (!LZ4_streamHCPtr) return 0; /* support free on NULL */ if (!LZ4_streamHCPtr) return 0; /* support free on NULL */
FREEMEM(LZ4_streamHCPtr); FREEMEM(LZ4_streamHCPtr);
@ -981,7 +965,8 @@ int LZ4_freeStreamHC(LZ4_streamHC_t *LZ4_streamHCPtr) {
} }
LZ4_streamHC_t *LZ4_initStreamHC(void *buffer, size_t size) { LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)
{
LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer; LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;
if (buffer == NULL) return NULL; if (buffer == NULL) return NULL;
if (size < sizeof(LZ4_streamHC_t)) return NULL; if (size < sizeof(LZ4_streamHC_t)) return NULL;
@ -1004,12 +989,14 @@ LZ4_streamHC_t *LZ4_initStreamHC(void *buffer, size_t size) {
} }
/* just a stub */ /* just a stub */
void LZ4_resetStreamHC(LZ4_streamHC_t *LZ4_streamHCPtr, int compressionLevel) { void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
{
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel); LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
} }
void LZ4_resetStreamHC_fast(LZ4_streamHC_t *LZ4_streamHCPtr, int compressionLevel) { void LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
{
DEBUGLOG(4, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel); DEBUGLOG(4, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel);
if (LZ4_streamHCPtr->internal_donotuse.dirty) { if (LZ4_streamHCPtr->internal_donotuse.dirty) {
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
@ -1022,31 +1009,33 @@ void LZ4_resetStreamHC_fast(LZ4_streamHC_t *LZ4_streamHCPtr, int compressionLeve
LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel); LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
} }
void LZ4_setCompressionLevel(LZ4_streamHC_t *LZ4_streamHCPtr, int compressionLevel) { void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
{
DEBUGLOG(5, "LZ4_setCompressionLevel(%p, %d)", LZ4_streamHCPtr, compressionLevel); DEBUGLOG(5, "LZ4_setCompressionLevel(%p, %d)", LZ4_streamHCPtr, compressionLevel);
if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT; if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT;
if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX; if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX;
LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel; LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel;
} }
void LZ4_favorDecompressionSpeed(LZ4_streamHC_t *LZ4_streamHCPtr, int favor) { void LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor)
{
LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0); LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0);
} }
/* LZ4_loadDictHC() : /* LZ4_loadDictHC() :
* LZ4_streamHCPtr is presumed properly initialized */ * LZ4_streamHCPtr is presumed properly initialized */
int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,
const char *dictionary, int dictSize) { const char* dictionary, int dictSize)
{
LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
DEBUGLOG(4, "LZ4_loadDictHC(%p, %p, %d)", LZ4_streamHCPtr, dictionary, dictSize); DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d)", LZ4_streamHCPtr, dictionary, dictSize);
assert(LZ4_streamHCPtr != NULL); assert(LZ4_streamHCPtr != NULL);
if (dictSize > 64 KB) { if (dictSize > 64 KB) {
dictionary += (size_t)dictSize - 64 KB; dictionary += (size_t)dictSize - 64 KB;
dictSize = 64 KB; dictSize = 64 KB;
} }
/* need a full initialization, there are bad side-effects when using resetFast() */ /* need a full initialization, there are bad side-effects when using resetFast() */
{ { int const cLevel = ctxPtr->compressionLevel;
int const cLevel = ctxPtr->compressionLevel;
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel); LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel);
} }
@ -1062,7 +1051,8 @@ void LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC
/* compression */ /* compression */
static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal *ctxPtr, const BYTE *newBlock) { static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)
{
DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock); DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock);
if (ctxPtr->end >= ctxPtr->base + ctxPtr->dictLimit + 4) if (ctxPtr->end >= ctxPtr->base + ctxPtr->dictLimit + 4)
LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */ LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */
@ -1082,7 +1072,8 @@ static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal *ctxPtr, const BYTE *newBl
static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr, static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
const char* src, char* dst, const char* src, char* dst,
int* srcSizePtr, int dstCapacity, int* srcSizePtr, int dstCapacity,
limitedOutput_directive limit) { limitedOutput_directive limit)
{
LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
DEBUGLOG(4, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d)", DEBUGLOG(4, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d)",
LZ4_streamHCPtr, src, *srcSizePtr); LZ4_streamHCPtr, src, *srcSizePtr);
@ -1102,8 +1093,7 @@ static int LZ4_compressHC_continue_generic(LZ4_streamHC_t *LZ4_streamHCPtr,
LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src); LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);
/* Check overlapping input/dictionary space */ /* Check overlapping input/dictionary space */
{ { const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;
const BYTE *sourceEnd = (const BYTE *) src + *srcSizePtr;
const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit; const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;
const BYTE* const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit; const BYTE* const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit;
if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) { if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {
@ -1116,14 +1106,16 @@ static int LZ4_compressHC_continue_generic(LZ4_streamHC_t *LZ4_streamHCPtr,
return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit); return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);
} }
int LZ4_compress_HC_continue(LZ4_streamHC_t *LZ4_streamHCPtr, const char *src, char *dst, int srcSize, int dstCapacity) { int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)
{
if (dstCapacity < LZ4_compressBound(srcSize)) if (dstCapacity < LZ4_compressBound(srcSize))
return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput); return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);
else else
return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited); return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited);
} }
int LZ4_compress_HC_continue_destSize(LZ4_streamHC_t *LZ4_streamHCPtr, const char *src, char *dst, int *srcSizePtr, int targetDestSize) { int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)
{
return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput); return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput);
} }
@ -1131,7 +1123,8 @@ int LZ4_compress_HC_continue_destSize(LZ4_streamHC_t *LZ4_streamHCPtr, const cha
/* dictionary saving */ /* dictionary saving */
int LZ4_saveDictHC(LZ4_streamHC_t *LZ4_streamHCPtr, char *safeBuffer, int dictSize) { int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
{
LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse; LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit)); int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit));
DEBUGLOG(4, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize); DEBUGLOG(4, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);
@ -1139,8 +1132,7 @@ int LZ4_saveDictHC(LZ4_streamHC_t *LZ4_streamHCPtr, char *safeBuffer, int dictSi
if (dictSize < 4) dictSize = 0; if (dictSize < 4) dictSize = 0;
if (dictSize > prefixSize) dictSize = prefixSize; if (dictSize > prefixSize) dictSize = prefixSize;
memmove(safeBuffer, streamPtr->end - dictSize, dictSize); memmove(safeBuffer, streamPtr->end - dictSize, dictSize);
{ { U32 const endIndex = (U32)(streamPtr->end - streamPtr->base);
U32 const endIndex = (U32)(streamPtr->end - streamPtr->base);
streamPtr->end = (const BYTE*)safeBuffer + dictSize; streamPtr->end = (const BYTE*)safeBuffer + dictSize;
streamPtr->base = streamPtr->end - endIndex; streamPtr->base = streamPtr->end - endIndex;
streamPtr->dictLimit = endIndex - (U32)dictSize; streamPtr->dictLimit = endIndex - (U32)dictSize;
@ -1175,35 +1167,41 @@ int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }
/* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t) /* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)
* @return : 0 on success, !=0 if error */ * @return : 0 on success, !=0 if error */
int LZ4_resetStreamStateHC(void *state, char *inputBuffer) { int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
{
LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4)); LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));
if (hc4 == NULL) return 1; /* init failed */ if (hc4 == NULL) return 1; /* init failed */
LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer); LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
return 0; return 0;
} }
void *LZ4_createHC(const char *inputBuffer) { void* LZ4_createHC (const char* inputBuffer)
{
LZ4_streamHC_t* const hc4 = LZ4_createStreamHC(); LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();
if (hc4 == NULL) return NULL; /* not enough memory */ if (hc4 == NULL) return NULL; /* not enough memory */
LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer); LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
return hc4; return hc4;
} }
int LZ4_freeHC(void *LZ4HC_Data) { int LZ4_freeHC (void* LZ4HC_Data)
{
if (!LZ4HC_Data) return 0; /* support free on NULL */ if (!LZ4HC_Data) return 0; /* support free on NULL */
FREEMEM(LZ4HC_Data); FREEMEM(LZ4HC_Data);
return 0; return 0;
} }
int LZ4_compressHC2_continue(void *LZ4HC_Data, const char *src, char *dst, int srcSize, int cLevel) { int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
{
return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited); return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);
} }
int LZ4_compressHC2_limitedOutput_continue(void *LZ4HC_Data, const char *src, char *dst, int srcSize, int dstCapacity, int cLevel) { int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
{
return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput); return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);
} }
char *LZ4_slideInputBufferHC(void *LZ4HC_Data) { char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
{
LZ4_streamHC_t *ctx = (LZ4_streamHC_t*)LZ4HC_Data; LZ4_streamHC_t *ctx = (LZ4_streamHC_t*)LZ4HC_Data;
const BYTE *bufferStart = ctx->internal_donotuse.base + ctx->internal_donotuse.lowLimit; const BYTE *bufferStart = ctx->internal_donotuse.base + ctx->internal_donotuse.lowLimit;
LZ4_resetStreamHC_fast(ctx, ctx->internal_donotuse.compressionLevel); LZ4_resetStreamHC_fast(ctx, ctx->internal_donotuse.compressionLevel);
@ -1223,7 +1221,8 @@ typedef struct {
} LZ4HC_optimal_t; } LZ4HC_optimal_t;
/* price in bytes */ /* price in bytes */
LZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen) { LZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen)
{
int price = litlen; int price = litlen;
assert(litlen >= 0); assert(litlen >= 0);
if (litlen >= (int)RUN_MASK) if (litlen >= (int)RUN_MASK)
@ -1233,7 +1232,8 @@ LZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen) {
/* requires mlen >= MINMATCH */ /* requires mlen >= MINMATCH */
LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen) { LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)
{
int price = 1 + 2 ; /* token + 16-bit offset */ int price = 1 + 2 ; /* token + 16-bit offset */
assert(litlen >= 0); assert(litlen >= 0);
assert(mlen >= MINMATCH); assert(mlen >= MINMATCH);
@ -1257,7 +1257,8 @@ LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal *const ctx,
const BYTE* ip, const BYTE* const iHighLimit, const BYTE* ip, const BYTE* const iHighLimit,
int minLen, int nbSearches, int minLen, int nbSearches,
const dictCtx_directive dict, const dictCtx_directive dict,
const HCfavor_e favorDecSpeed) { const HCfavor_e favorDecSpeed)
{
LZ4HC_match_t match = { 0 , 0 }; LZ4HC_match_t match = { 0 , 0 };
const BYTE* matchPtr = NULL; const BYTE* matchPtr = NULL;
/* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos), /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
@ -1284,9 +1285,15 @@ static int LZ4HC_compress_optimal(LZ4HC_CCtx_internal *ctx,
const limitedOutput_directive limit, const limitedOutput_directive limit,
int const fullUpdate, int const fullUpdate,
const dictCtx_directive dict, const dictCtx_directive dict,
const HCfavor_e favorDecSpeed) { const HCfavor_e favorDecSpeed)
{
int retval = 0;
#define TRAILING_LITERALS 3 #define TRAILING_LITERALS 3
#ifdef LZ4HC_HEAPMODE
LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)malloc(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS));
#else
LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS]; /* ~64 KB, which is a bit large for stack... */ LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS]; /* ~64 KB, which is a bit large for stack... */
#endif
const BYTE* ip = (const BYTE*) source; const BYTE* ip = (const BYTE*) source;
const BYTE* anchor = ip; const BYTE* anchor = ip;
@ -1298,6 +1305,9 @@ static int LZ4HC_compress_optimal(LZ4HC_CCtx_internal *ctx,
BYTE* oend = op + dstCapacity; BYTE* oend = op + dstCapacity;
/* init */ /* init */
#ifdef LZ4HC_HEAPMODE
if (opt == NULL) goto _return_label;
#endif
DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity); DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity);
*srcSizePtr = 0; *srcSizePtr = 0;
if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */ if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
@ -1324,8 +1334,7 @@ static int LZ4HC_compress_optimal(LZ4HC_CCtx_internal *ctx,
} }
/* set prices for first positions (literals) */ /* set prices for first positions (literals) */
{ { int rPos;
int rPos;
for (rPos = 0 ; rPos < MINMATCH ; rPos++) { for (rPos = 0 ; rPos < MINMATCH ; rPos++) {
int const cost = LZ4HC_literalsPrice(llen + rPos); int const cost = LZ4HC_literalsPrice(llen + rPos);
opt[rPos].mlen = 1; opt[rPos].mlen = 1;
@ -1334,11 +1343,9 @@ static int LZ4HC_compress_optimal(LZ4HC_CCtx_internal *ctx,
opt[rPos].price = cost; opt[rPos].price = cost;
DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup", DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",
rPos, cost, opt[rPos].litlen); rPos, cost, opt[rPos].litlen);
} } }
}
/* set prices using initial match */ /* set prices using initial match */
{ { int mlen = MINMATCH;
int mlen = MINMATCH;
int const matchML = firstMatch.len; /* necessarily < sufficient_len < LZ4_OPT_NUM */ int const matchML = firstMatch.len; /* necessarily < sufficient_len < LZ4_OPT_NUM */
int const offset = firstMatch.off; int const offset = firstMatch.off;
assert(matchML < LZ4_OPT_NUM); assert(matchML < LZ4_OPT_NUM);
@ -1350,11 +1357,9 @@ static int LZ4HC_compress_optimal(LZ4HC_CCtx_internal *ctx,
opt[mlen].price = cost; opt[mlen].price = cost;
DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i) -- initial setup", DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i) -- initial setup",
mlen, cost, mlen); mlen, cost, mlen);
} } }
}
last_match_pos = firstMatch.len; last_match_pos = firstMatch.len;
{ { int addLit;
int addLit;
for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) { for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {
opt[last_match_pos+addLit].mlen = 1; /* literal */ opt[last_match_pos+addLit].mlen = 1; /* literal */
opt[last_match_pos+addLit].off = 0; opt[last_match_pos+addLit].off = 0;
@ -1362,8 +1367,7 @@ static int LZ4HC_compress_optimal(LZ4HC_CCtx_internal *ctx,
opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit); opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);
DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup", DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",
last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit); last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);
} } }
}
/* check further positions */ /* check further positions */
for (cur = 1; cur < last_match_pos; cur++) { for (cur = 1; cur < last_match_pos; cur++) {
@ -1402,8 +1406,7 @@ static int LZ4HC_compress_optimal(LZ4HC_CCtx_internal *ctx,
} }
/* before match : set price with literals at beginning */ /* before match : set price with literals at beginning */
{ { int const baseLitlen = opt[cur].litlen;
int const baseLitlen = opt[cur].litlen;
int litlen; int litlen;
for (litlen = 1; litlen < MINMATCH; litlen++) { for (litlen = 1; litlen < MINMATCH; litlen++) {
int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen); int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen);
@ -1415,13 +1418,10 @@ static int LZ4HC_compress_optimal(LZ4HC_CCtx_internal *ctx,
opt[pos].price = price; opt[pos].price = price;
DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)",
pos, price, opt[pos].litlen); pos, price, opt[pos].litlen);
} } } }
}
}
/* set prices using match at position = cur */ /* set prices using match at position = cur */
{ { int const matchML = newMatch.len;
int const matchML = newMatch.len;
int ml = MINMATCH; int ml = MINMATCH;
assert(cur + newMatch.len < LZ4_OPT_NUM); assert(cur + newMatch.len < LZ4_OPT_NUM);
@ -1454,20 +1454,16 @@ static int LZ4HC_compress_optimal(LZ4HC_CCtx_internal *ctx,
opt[pos].off = offset; opt[pos].off = offset;
opt[pos].litlen = ll; opt[pos].litlen = ll;
opt[pos].price = price; opt[pos].price = price;
} } } }
}
}
/* complete following positions with literals */ /* complete following positions with literals */
{ { int addLit;
int addLit;
for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) { for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {
opt[last_match_pos+addLit].mlen = 1; /* literal */ opt[last_match_pos+addLit].mlen = 1; /* literal */
opt[last_match_pos+addLit].off = 0; opt[last_match_pos+addLit].off = 0;
opt[last_match_pos+addLit].litlen = addLit; opt[last_match_pos+addLit].litlen = addLit;
opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit); opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);
DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit); DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);
} } }
}
} /* for (cur = 1; cur <= last_match_pos; cur++) */ } /* for (cur = 1; cur <= last_match_pos; cur++) */
assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS); assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS);
@ -1479,8 +1475,7 @@ encode: /* cur, last_match_pos, best_mlen, best_off must be set */
assert(cur < LZ4_OPT_NUM); assert(cur < LZ4_OPT_NUM);
assert(last_match_pos >= 1); /* == 1 when only one candidate */ assert(last_match_pos >= 1); /* == 1 when only one candidate */
DEBUGLOG(6, "reverse traversal, looking for shortest path (last_match_pos=%i)", last_match_pos); DEBUGLOG(6, "reverse traversal, looking for shortest path (last_match_pos=%i)", last_match_pos);
{ { int candidate_pos = cur;
int candidate_pos = cur;
int selected_matchLength = best_mlen; int selected_matchLength = best_mlen;
int selected_offset = best_off; int selected_offset = best_off;
while (1) { /* from end to beginning */ while (1) { /* from end to beginning */
@ -1494,12 +1489,10 @@ encode: /* cur, last_match_pos, best_mlen, best_off must be set */
if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */ if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */
assert(next_matchLength > 0); /* can be 1, means literal */ assert(next_matchLength > 0); /* can be 1, means literal */
candidate_pos -= next_matchLength; candidate_pos -= next_matchLength;
} } }
}
/* encode all recorded sequences in order */ /* encode all recorded sequences in order */
{ { int rPos = 0; /* relative position (to ip) */
int rPos = 0; /* relative position (to ip) */
while (rPos < last_match_pos) { while (rPos < last_match_pos) {
int const ml = opt[rPos].mlen; int const ml = opt[rPos].mlen;
int const offset = opt[rPos].off; int const offset = opt[rPos].off;
@ -1510,19 +1503,20 @@ encode: /* cur, last_match_pos, best_mlen, best_off must be set */
opSaved = op; opSaved = op;
if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend) ) /* updates ip, op and anchor */ if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend) ) /* updates ip, op and anchor */
goto _dest_overflow; goto _dest_overflow;
} } }
}
} /* while (ip <= mflimit) */ } /* while (ip <= mflimit) */
_last_literals: _last_literals:
/* Encode Last Literals */ /* Encode Last Literals */
{ { size_t lastRunSize = (size_t)(iend - anchor); /* literals */
size_t lastRunSize = (size_t)(iend - anchor); /* literals */
size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255; size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255;
size_t const totalSize = 1 + litLength + lastRunSize; size_t const totalSize = 1 + litLength + lastRunSize;
if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */ if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */
if (limit && (op + totalSize > oend)) { if (limit && (op + totalSize > oend)) {
if (limit == limitedOutput) return 0; /* Check output limit */ if (limit == limitedOutput) { /* Check output limit */
retval = 0;
goto _return_label;
}
/* adapt lastRunSize to fill 'dst' */ /* adapt lastRunSize to fill 'dst' */
lastRunSize = (size_t)(oend - op) - 1; lastRunSize = (size_t)(oend - op) - 1;
litLength = (lastRunSize + 255 - RUN_MASK) / 255; litLength = (lastRunSize + 255 - RUN_MASK) / 255;
@ -1544,12 +1538,17 @@ _last_literals:
/* End */ /* End */
*srcSizePtr = (int) (((const char*)ip) - source); *srcSizePtr = (int) (((const char*)ip) - source);
return (int)((char *)op - dst); retval = (int) ((char*)op-dst);
goto _return_label;
_dest_overflow: _dest_overflow:
if (limit == fillOutput) { if (limit == fillOutput) {
op = opSaved; /* restore correct out pointer */ op = opSaved; /* restore correct out pointer */
goto _last_literals; goto _last_literals;
} }
return 0; _return_label:
#ifdef LZ4HC_HEAPMODE
free(opt);
#endif
return retval;
} }

View file

@ -202,7 +202,8 @@ LZ4LIB_API int LZ4_saveDictHC(LZ4_streamHC_t *streamHCPtr, char *safeBuffer, int
#include <stdint.h> #include <stdint.h>
typedef struct LZ4HC_CCtx_internal LZ4HC_CCtx_internal; typedef struct LZ4HC_CCtx_internal LZ4HC_CCtx_internal;
struct LZ4HC_CCtx_internal { struct LZ4HC_CCtx_internal
{
uint32_t hashTable[LZ4HC_HASHTABLESIZE]; uint32_t hashTable[LZ4HC_HASHTABLESIZE];
uint16_t chainTable[LZ4HC_MAXD]; uint16_t chainTable[LZ4HC_MAXD];
const uint8_t* end; /* next block here to continue on current prefix */ const uint8_t* end; /* next block here to continue on current prefix */
@ -221,7 +222,8 @@ struct LZ4HC_CCtx_internal {
#else #else
typedef struct LZ4HC_CCtx_internal LZ4HC_CCtx_internal; typedef struct LZ4HC_CCtx_internal LZ4HC_CCtx_internal;
struct LZ4HC_CCtx_internal { struct LZ4HC_CCtx_internal
{
unsigned int hashTable[LZ4HC_HASHTABLESIZE]; unsigned int hashTable[LZ4HC_HASHTABLESIZE];
unsigned short chainTable[LZ4HC_MAXD]; unsigned short chainTable[LZ4HC_MAXD];
const unsigned char* end; /* next block here to continue on current prefix */ const unsigned char* end; /* next block here to continue on current prefix */