Youcancontacttheauthorat: -LZ4sourcerepository:https://github.com/lz4/lz4 -LZ4publicforum:https://groups.google.com/forum/#!forum/lz4c
*/ /* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */
#ifdefined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2) /* lie to the compiler about data alignment; use with caution */ static U64 LZ4_read64(constvoid* memPtr) { return *(const U64*) memPtr; }
#elifdefined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1) /* __pack instructions are safer, but compiler specific */
LZ4_PACK(typedefstruct { U64 u64; }) LZ4_unalign64; static U64 LZ4_read64(constvoid* ptr) { return ((const LZ4_unalign64*)ptr)->u64; }
/* input sanitization */
DEBUGLOG(5, "LZ4MID_compress (%i bytes)", *srcSizePtr); if (dict == usingDictCtxHc) DEBUGLOG(5, "usingDictCtxHc");
assert(*srcSizePtr >= 0); if (*srcSizePtr) assert(src != NULL); if (maxOutputSize) assert(dst != NULL); if (*srcSizePtr < 0) return0; /* invalid */ if (maxOutputSize < 0) return0; /* invalid */ if (*srcSizePtr > LZ4_MAX_INPUT_SIZE) { /* forbidden: no input is allowed to be that large */ return0;
} if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */ if (*srcSizePtr < LZ4_minLength) goto _lz4mid_last_literals; /* Input too small, no compression (all literals) */
/* main loop */ while (ip <= mflimit) { const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx; /* search long match */
{ U32 const h8 = LZ4MID_hash8Ptr(ip);
U32 const pos8 = hash8Table[h8];
assert(h8 < LZ4MID_HASHTABLESIZE);
assert(pos8 < ipIndex);
LZ4MID_addPosition(hash8Table, h8, ipIndex); if (ipIndex - pos8 <= LZ4_DISTANCE_MAX) { /* match candidate found */ if (pos8 >= prefixIdx) { const BYTE* const matchPtr = prefixPtr + pos8 - prefixIdx;
assert(matchPtr < ip);
matchLength = LZ4_count(ip, matchPtr, matchlimit); if (matchLength >= MINMATCH) {
DEBUGLOG(7, "found long match at pos %u (len=%u)", pos8, matchLength);
matchDistance = ipIndex - pos8; goto _lz4mid_encode_sequence;
}
} else { if (pos8 >= dictIdx) { /* extDict match candidate */ const BYTE* const matchPtr = dictStart + (pos8 - dictIdx); const size_t safeLen = MIN(prefixIdx - pos8, (size_t)(matchlimit - ip));
matchLength = LZ4_count(ip, matchPtr, ip + safeLen); if (matchLength >= MINMATCH) {
DEBUGLOG(7, "found long match at ExtDict pos %u (len=%u)", pos8, matchLength);
matchDistance = ipIndex - pos8; goto _lz4mid_encode_sequence;
}
}
}
} } /* search short match */
{ U32 const h4 = LZ4MID_hash4Ptr(ip);
U32 const pos4 = hash4Table[h4];
assert(h4 < LZ4MID_HASHTABLESIZE);
assert(pos4 < ipIndex);
LZ4MID_addPosition(hash4Table, h4, ipIndex); if (ipIndex - pos4 <= LZ4_DISTANCE_MAX) { /* match candidate found */ if (pos4 >= prefixIdx) { /* only search within prefix */ const BYTE* const matchPtr = prefixPtr + (pos4 - prefixIdx);
assert(matchPtr < ip);
assert(matchPtr >= prefixPtr);
matchLength = LZ4_count(ip, matchPtr, matchlimit); if (matchLength >= MINMATCH) { /* short match found, let's just check ip+1 for longer */
U32 const h8 = LZ4MID_hash8Ptr(ip+1);
U32 const pos8 = hash8Table[h8];
U32 const m2Distance = ipIndex + 1 - pos8;
matchDistance = ipIndex - pos4; if ( m2Distance <= LZ4_DISTANCE_MAX
&& pos8 >= prefixIdx /* only search within prefix */
&& likely(ip < mflimit)
) { const BYTE* const m2Ptr = prefixPtr + (pos8 - prefixIdx); unsigned ml2 = LZ4_count(ip+1, m2Ptr, matchlimit); if (ml2 > matchLength) {
LZ4MID_addPosition(hash8Table, h8, ipIndex+1);
ip++;
matchLength = ml2;
matchDistance = m2Distance;
} } goto _lz4mid_encode_sequence;
}
} else { if (pos4 >= dictIdx) { /* extDict match candidate */ const BYTE* const matchPtr = dictStart + (pos4 - dictIdx); const size_t safeLen = MIN(prefixIdx - pos4, (size_t)(matchlimit - ip));
matchLength = LZ4_count(ip, matchPtr, ip + safeLen); if (matchLength >= MINMATCH) {
DEBUGLOG(7, "found match at ExtDict pos %u (len=%u)", pos4, matchLength);
matchDistance = ipIndex - pos4; goto _lz4mid_encode_sequence;
}
}
}
} } /* no match found in prefix */ if ( (dict == usingDictCtxHc)
&& (ipIndex - gDictEndIndex < LZ4_DISTANCE_MAX - 8) ) { /* search a match into external dictionary */
LZ4HC_match_t dMatch = searchIntoDict(ip, ipIndex,
matchlimit,
ctx->dictCtx, gDictEndIndex); if (dMatch.len >= MINMATCH) {
DEBUGLOG(7, "found Dictionary match (offset=%i)", dMatch.off);
assert(dMatch.back == 0);
matchLength = (unsigned)dMatch.len;
matchDistance = (unsigned)dMatch.off; goto _lz4mid_encode_sequence;
}
} /* no match found */
ip += 1 + ((ip-anchor) >> 9); /* skip faster over incompressible data */ continue;
DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch"); /* First Match */
LZ4HC_Insert(hc4, ip); /* insert all prior positions up to ip (excluded) */
matchIndex = hashTable[LZ4HC_hashPtr(ip)];
DEBUGLOG(7, "First candidate match for pos %u found at index %u / %u (lowestMatchIndex)",
ipIndex, matchIndex, lowestMatchIndex);
while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) { int matchLength=0;
nbAttempts--;
assert(matchIndex < ipIndex); if (favorDecSpeed && (ipIndex - matchIndex < 8)) { /* do nothing:
* favorDecSpeed intentionally skips matches with offset < 8 */
} elseif (matchIndex >= prefixIdx) { /* within current Prefix */ const BYTE* const matchPtr = prefixPtr + (matchIndex - prefixIdx);
assert(matchPtr < ip);
assert(longest >= 1); if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) { if (LZ4_read32(matchPtr) == pattern) { intconst back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, prefixPtr) : 0;
matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);
matchLength -= back; if (matchLength > longest) {
longest = matchLength;
offset = (int)(ipIndex - matchIndex);
sBack = back;
DEBUGLOG(7, "Found match of len=%i within prefix, offset=%i, back=%i", longest, offset, -back);
} } }
} else { /* lowestMatchIndex <= matchIndex < dictLimit : within Ext Dict */ const BYTE* const matchPtr = dictStart + (matchIndex - dictIdx);
assert(matchIndex >= dictIdx); if ( likely(matchIndex <= prefixIdx - 4)
&& (LZ4_read32(matchPtr) == pattern) ) { int back = 0; const BYTE* vLimit = ip + (prefixIdx - matchIndex); if (vLimit > iHighLimit) vLimit = iHighLimit;
matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH; if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))
matchLength += LZ4_count(ip+matchLength, prefixPtr, iHighLimit);
back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0;
matchLength -= back; if (matchLength > longest) {
longest = matchLength;
offset = (int)(ipIndex - matchIndex);
sBack = back;
DEBUGLOG(7, "Found match of len=%i within dict, offset=%i, back=%i", longest, offset, -back);
} } }
if (chainSwap && matchLength==longest) { /* better match => select a better chain */
assert(lookBackLength==0); /* search forward only */ if (matchIndex + (U32)longest <= ipIndex) { intconst kTrigger = 4;
U32 distanceToNextMatch = 1; intconst end = longest - MINMATCH + 1; int step = 1; int accel = 1 << kTrigger; int pos; for (pos = 0; pos < end; pos += step) {
U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos);
step = (accel++ >> kTrigger); if (candidateDist > distanceToNextMatch) {
distanceToNextMatch = candidateDist;
matchChainPos = (U32)pos;
accel = 1 << kTrigger;
} } if (distanceToNextMatch > 1) { if (distanceToNextMatch > matchIndex) break; /* avoid overflow */
matchIndex -= distanceToNextMatch; continue;
} } }
{ U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex); if (patternAnalysis && distNextMatch==1 && matchChainPos==0) {
U32 const matchCandidateIdx = matchIndex-1; /* may be a repeated pattern */ if (repeat == rep_untested) { if ( ((pattern & 0xFFFF) == (pattern >> 16))
& ((pattern & 0xFF) == (pattern >> 24)) ) {
DEBUGLOG(7, "Repeat pattern detected, char %02X", pattern >> 24);
repeat = rep_confirmed;
srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);
} else {
repeat = rep_not;
} } if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)
&& LZ4HC_protectDictEnd(prefixIdx, matchCandidateIdx) ) { constint extDict = matchCandidateIdx < prefixIdx; const BYTE* const matchPtr = extDict ? dictStart + (matchCandidateIdx - dictIdx) : prefixPtr + (matchCandidateIdx - prefixIdx); if (LZ4_read32(matchPtr) == pattern) { /* good candidate */ const BYTE* const iLimit = extDict ? dictEnd : iHighLimit;
size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern); if (extDict && matchPtr + forwardPatternLength == iLimit) {
U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern);
forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern);
}
{ const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr;
size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);
size_t currentSegmentLength; if (!extDict
&& matchPtr - backLength == prefixPtr
&& dictIdx < prefixIdx) {
U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern);
backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern);
} /* Limit backLength not go further than lowestMatchIndex */
backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex);
assert(matchCandidateIdx - backLength >= lowestMatchIndex);
currentSegmentLength = backLength + forwardPatternLength; /* Adjust to end of pattern if the source pattern fits, otherwise the beginning of the pattern */ if ( (currentSegmentLength >= srcPatternLength) /* current pattern segment large enough to contain full srcPatternLength */
&& (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */
U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength; /* best position, full pattern, might be followed by more match */ if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex))
matchIndex = newMatchIndex; else { /* Can only happen if started in the prefix */
assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);
matchIndex = prefixIdx;
}
} else {
U32 const newMatchIndex = matchCandidateIdx - (U32)backLength; /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */ if (!LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) {
assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);
matchIndex = prefixIdx;
} else {
matchIndex = newMatchIndex; if (lookBackLength==0) { /* no back possible */
size_t const maxML = MIN(currentSegmentLength, srcPatternLength); if ((size_t)longest < maxML) {
assert(prefixPtr - prefixIdx + matchIndex != ip); if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break;
assert(maxML < 2 GB);
longest = (int)maxML;
offset = (int)(ipIndex - matchIndex);
assert(sBack == 0);
DEBUGLOG(7, "Found repeat pattern match of len=%i, offset=%i", longest, offset);
}
{ U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex); if (distToNextPattern > matchIndex) break; /* avoid overflow */
matchIndex -= distToNextPattern;
} } } } } continue;
} }
} } /* PA optimization */
LZ4_FORCE_INLINE LZ4HC_match_t
LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index table will be updated */ const BYTE* const ip, const BYTE* const iLimit, constint maxNbAttempts, constint patternAnalysis, const dictCtx_directive dict)
{
DEBUGLOG(7, "LZ4HC_InsertAndFindBestMatch"); /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos), *butthiswon'tbethecasehere,aswedefineiLowLimit==ip,
* so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */ return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, maxNbAttempts, patternAnalysis, 0/*chainSwap*/, dict, favorCompressionRatio);
}
/* init */
DEBUGLOG(5, "LZ4HC_compress_hashChain (dict?=>%i)", dict);
*srcSizePtr = 0; if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */ if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
/* Main Loop */ while (ip <= mflimit) {
m1 = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, maxNbAttempts, patternAnalysis, dict); if (m1.len<MINMATCH) { ip++; continue; }
/* saved, in case we would skip too much */
start0 = ip; m0 = m1;
_Search2:
DEBUGLOG(7, "_Search2 (currently found match of size %i)", m1.len); if (ip+m1.len <= mflimit) {
start2 = ip + m1.len - 2;
m2 = LZ4HC_InsertAndGetWiderMatch(ctx,
start2, ip + 0, matchlimit, m1.len,
maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
start2 += m2.back;
} else {
m2 = nomatch; /* do not search further */
}
if (m2.len <= m1.len) { /* No better match => encode ML1 immediately */
optr = op; if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
m1.len, m1.off,
limit, oend) ) goto _dest_overflow; continue;
}
if (start0 < ip) { /* first match was skipped at least once */ if (start2 < ip + m0.len) { /* squeezing ML1 between ML0(original ML1) and ML2 */
ip = start0; m1 = m0; /* restore initial Match1 */
} }
/* Here, start0==ip */ if ((start2 - ip) < 3) { /* First Match too small : removed */
ip = start2;
m1 = m2; goto _Search2;
}
_Search3: if ((start2 - ip) < OPTIMAL_ML) { int correction; int new_ml = m1.len; if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML; if (ip+new_ml > start2 + m2.len - MINMATCH)
new_ml = (int)(start2 - ip) + m2.len - MINMATCH;
correction = new_ml - (int)(start2 - ip); if (correction > 0) {
start2 += correction;
m2.len -= correction;
}
}
if (m3.len <= m2.len) { /* No better match => encode ML1 and ML2 */ /* ip & ref are known; Now for ml */ if (start2 < ip+m1.len) m1.len = (int)(start2 - ip); /* Now, encode 2 sequences */
optr = op; if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
m1.len, m1.off,
limit, oend) ) goto _dest_overflow;
ip = start2;
optr = op; if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
m2.len, m2.off,
limit, oend) ) {
m1 = m2; goto _dest_overflow;
} continue;
}
if (start3 < ip+m1.len+3) { /* Not enough space for match 2 : remove it */ if (start3 >= (ip+m1.len)) { /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */ if (start2 < ip+m1.len) { int correction = (int)(ip+m1.len - start2);
start2 += correction;
m2.len -= correction; if (m2.len < MINMATCH) {
start2 = start3;
m2 = m3;
}
}
optr = op; if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
m1.len, m1.off,
limit, oend) ) goto _dest_overflow;
ip = start3;
m1 = m3;
if (limit == fillOutput && dstCapacity < 1) return0; /* Impossible to store anything */ if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return0; /* Unsupported input size (too large or negative) */
/* state is presumed correctly initialized,
* in which case its size and alignment have already been validate */ int LZ4_compress_HC_extStateHC_fastReset (void* state, constchar* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
{
LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse; if (!LZ4_isAligned(state, LZ4_streamHC_t_alignment())) return0;
LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel);
LZ4HC_init_internal (ctx, (const BYTE*)src); if (dstCapacity < LZ4_compressBound(srcSize)) return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput); else return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited);
}
int LZ4_compress_HC_extStateHC (void* state, constchar* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
{
LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx)); if (ctx==NULL) return0; /* init failure */ return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel);
}
int LZ4_compress_HC(constchar* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
{ int cSize; #ifdefined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t)); if (statePtr==NULL) return0; #else
LZ4_streamHC_t state;
LZ4_streamHC_t* const statePtr = &state; #endif
DEBUGLOG(5, "LZ4_compress_HC")
cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel); #ifdefined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
FREEMEM(statePtr); #endif return cSize;
}
/* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */ int LZ4_compress_HC_destSize(void* state, constchar* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)
{
LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx)); if (ctx==NULL) return0; /* init failure */
LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source);
LZ4_setCompressionLevel(ctx, cLevel); return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput);
}
/* Only one memory segment for extDict, so any previous extDict is lost at this stage */
ctxPtr->lowLimit = ctxPtr->dictLimit;
ctxPtr->dictStart = ctxPtr->prefixStart;
ctxPtr->dictLimit += (U32)(ctxPtr->end - ctxPtr->prefixStart);
ctxPtr->prefixStart = newBlock;
ctxPtr->end = newBlock;
ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */
/* cannot reference an extDict and a dictCtx at the same time */
ctxPtr->dictCtx = NULL;
}
/* ================================================ *LZ4Optimalparser(levels[LZ4HC_CLEVEL_OPT_MIN-LZ4HC_CLEVEL_MAX])
* ===============================================*/ typedefstruct { int price; int off; int mlen; int litlen;
} LZ4HC_optimal_t;
/* price in bytes */
LZ4_FORCE_INLINE int LZ4HC_literalsPrice(intconst litlen)
{ int price = litlen;
assert(litlen >= 0); if (litlen >= (int)RUN_MASK)
price += 1 + ((litlen-(int)RUN_MASK) / 255); return price;
}
/* check further positions */ for (cur = 1; cur < last_match_pos; cur++) { const BYTE* const curPtr = ip + cur;
LZ4HC_match_t newMatch;
if (curPtr > mflimit) break;
DEBUGLOG(7, "rPos:%u[%u] vs [%u]%u",
cur, opt[cur].price, opt[cur+1].price, cur+1); if (fullUpdate) { /* not useful to search here if next position has same (or lower) cost */ if ( (opt[cur+1].price <= opt[cur].price) /* in some cases, next position has same cost, but cost rises sharply after, so a small match would still be beneficial */
&& (opt[cur+MINMATCH].price < opt[cur].price + 3/*min seq price*/) ) continue;
} else { /* not useful to search here if next position has same (or lower) cost */ if (opt[cur+1].price <= opt[cur].price) continue;
}
DEBUGLOG(7, "search at rPos:%u", cur); if (fullUpdate)
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, favorDecSpeed); if (!newMatch.len) continue;
encode: /* cur, last_match_pos, best_mlen, best_off must be set */
assert(cur < LZ4_OPT_NUM);
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);
{ int candidate_pos = cur; int selected_matchLength = best_mlen; int selected_offset = best_off; while (1) { /* from end to beginning */ intconst next_matchLength = opt[candidate_pos].mlen; /* can be 1, means literal */ intconst next_offset = opt[candidate_pos].off;
DEBUGLOG(7, "pos %i: sequence length %i", candidate_pos, selected_matchLength);
opt[candidate_pos].mlen = selected_matchLength;
opt[candidate_pos].off = selected_offset;
selected_matchLength = next_matchLength;
selected_offset = next_offset; if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */
assert(next_matchLength > 0); /* can be 1, means literal */
candidate_pos -= next_matchLength;
} }
/* encode all recorded sequences in order */
{ int rPos = 0; /* relative position (to ip) */ while (rPos < last_match_pos) { intconst ml = opt[rPos].mlen; intconst offset = opt[rPos].off; if (ml == 1) { ip++; rPos++; continue; } /* literal; note: can end up with several literals, in which case, skip them */
rPos += ml;
assert(ml >= MINMATCH);
assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));
opSaved = op; if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, offset, limit, oend) ) { /* updates ip, op and anchor */
ovml = ml;
ovoff = offset; goto _dest_overflow;
} } }
} /* while (ip <= mflimit) */
_last_literals: /* Encode Last Literals */
{ size_t lastRunSize = (size_t)(iend - anchor); /* literals */
size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
size_t const totalSize = 1 + llAdd + lastRunSize; if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */ if (limit && (op + totalSize > oend)) { if (limit == limitedOutput) { /* Check output limit */
retval = 0; goto _return_label;
} /* adapt lastRunSize to fill 'dst' */
lastRunSize = (size_t)(oend - op) - 1/*token*/;
llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
lastRunSize -= llAdd;
}
DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.