in lib/lz4/lz4.cc [485:695]
FORCE_INLINE int LZ4_compress_generic(void *const ctx, const char *const source, char *const dest,
const int inputSize, const int maxOutputSize,
const limitedOutput_directive outputLimited,
const tableType_t tableType, const dict_directive dict,
const dictIssue_directive dictIssue, const U32 acceleration) {
LZ4_stream_t_internal *const dictPtr = (LZ4_stream_t_internal *)ctx;
const BYTE *ip = (const BYTE *)source;
const BYTE *base;
const BYTE *lowLimit;
const BYTE *const lowRefLimit = ip - dictPtr->dictSize;
const BYTE *const dictionary = dictPtr->dictionary;
const BYTE *const dictEnd = dictionary + dictPtr->dictSize;
const size_t dictDelta = dictEnd - (const BYTE *)source;
const BYTE *anchor = (const BYTE *)source;
const BYTE *const iend = ip + inputSize;
const BYTE *const mflimit = iend - MFLIMIT;
const BYTE *const matchlimit = iend - LASTLITERALS;
BYTE *op = (BYTE *)dest;
BYTE *const olimit = op + maxOutputSize;
U32 forwardH;
size_t refDelta = 0;
/* Init conditions */
if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE)
return 0; /* Unsupported input size, too large (or negative) */
switch (dict) {
case noDict:
default:
base = (const BYTE *)source;
lowLimit = (const BYTE *)source;
break;
case withPrefix64k:
base = (const BYTE *)source - dictPtr->currentOffset;
lowLimit = (const BYTE *)source - dictPtr->dictSize;
break;
case usingExtDict:
base = (const BYTE *)source - dictPtr->currentOffset;
lowLimit = (const BYTE *)source;
break;
}
if ((tableType == byU16) && (inputSize >= LZ4_64Klimit))
return 0; /* Size too large (not within 64K limit) */
if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
/* First Byte */
LZ4_putPosition(ip, ctx, tableType, base);
ip++;
forwardH = LZ4_hashPosition(ip, tableType);
/* Main Loop */
for (;;) {
const BYTE *match;
BYTE *token;
{
const BYTE *forwardIp = ip;
unsigned step = 1;
unsigned searchMatchNb = acceleration << LZ4_skipTrigger;
/* Find a match */
do {
U32 h = forwardH;
ip = forwardIp;
forwardIp += step;
step = (searchMatchNb++ >> LZ4_skipTrigger);
if (unlikely(forwardIp > mflimit)) goto _last_literals;
match = LZ4_getPositionOnHash(h, ctx, tableType, base);
if (dict == usingExtDict) {
if (match < (const BYTE *)source) {
refDelta = dictDelta;
lowLimit = dictionary;
} else {
refDelta = 0;
lowLimit = (const BYTE *)source;
}
}
forwardH = LZ4_hashPosition(forwardIp, tableType);
LZ4_putPositionOnHash(ip, h, ctx, tableType, base);
} while (((dictIssue == dictSmall) ? (match < lowRefLimit) : 0) ||
((tableType == byU16) ? 0 : (match + MAX_DISTANCE < ip)) ||
(LZ4_read32(match + refDelta) != LZ4_read32(ip)));
}
/* Catch up */
while ((ip > anchor) && (match + refDelta > lowLimit) && (unlikely(ip[-1] == match[refDelta - 1]))) {
ip--;
match--;
}
{
/* Encode Literal length */
unsigned litLength = (unsigned)(ip - anchor);
token = op++;
if ((outputLimited) &&
(unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength / 255) > olimit)))
return 0; /* Check output limit */
if (litLength >= RUN_MASK) {
int len = (int)litLength - RUN_MASK;
*token = (RUN_MASK << ML_BITS);
for (; len >= 255; len -= 255) *op++ = 255;
*op++ = (BYTE)len;
} else
*token = (BYTE)(litLength << ML_BITS);
/* Copy Literals */
LZ4_wildCopy(op, anchor, op + litLength);
op += litLength;
}
_next_match:
/* Encode Offset */
LZ4_writeLE16(op, (U16)(ip - match));
op += 2;
/* Encode MatchLength */
{
unsigned matchLength;
if ((dict == usingExtDict) && (lowLimit == dictionary)) {
const BYTE *limit;
match += refDelta;
limit = ip + (dictEnd - match);
if (limit > matchlimit) limit = matchlimit;
matchLength = LZ4_count(ip + MINMATCH, match + MINMATCH, limit);
ip += MINMATCH + matchLength;
if (ip == limit) {
unsigned more = LZ4_count(ip, (const BYTE *)source, matchlimit);
matchLength += more;
ip += more;
}
} else {
matchLength = LZ4_count(ip + MINMATCH, match + MINMATCH, matchlimit);
ip += MINMATCH + matchLength;
}
if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength >> 8) > olimit)))
return 0; /* Check output limit */
if (matchLength >= ML_MASK) {
*token += ML_MASK;
matchLength -= ML_MASK;
for (; matchLength >= 510; matchLength -= 510) {
*op++ = 255;
*op++ = 255;
}
if (matchLength >= 255) {
matchLength -= 255;
*op++ = 255;
}
*op++ = (BYTE)matchLength;
} else
*token += (BYTE)(matchLength);
}
anchor = ip;
/* Test end of chunk */
if (ip > mflimit) break;
/* Fill table */
LZ4_putPosition(ip - 2, ctx, tableType, base);
/* Test next position */
match = LZ4_getPosition(ip, ctx, tableType, base);
if (dict == usingExtDict) {
if (match < (const BYTE *)source) {
refDelta = dictDelta;
lowLimit = dictionary;
} else {
refDelta = 0;
lowLimit = (const BYTE *)source;
}
}
LZ4_putPosition(ip, ctx, tableType, base);
if (((dictIssue == dictSmall) ? (match >= lowRefLimit) : 1) && (match + MAX_DISTANCE >= ip) &&
(LZ4_read32(match + refDelta) == LZ4_read32(ip))) {
token = op++;
*token = 0;
goto _next_match;
}
/* Prepare next loop */
forwardH = LZ4_hashPosition(++ip, tableType);
}
_last_literals:
/* Encode Last Literals */
{
const size_t lastRun = (size_t)(iend - anchor);
if ((outputLimited) &&
((op - (BYTE *)dest) + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > (U32)maxOutputSize))
return 0; /* Check output limit */
if (lastRun >= RUN_MASK) {
size_t accumulator = lastRun - RUN_MASK;
*op++ = RUN_MASK << ML_BITS;
for (; accumulator >= 255; accumulator -= 255) *op++ = 255;
*op++ = (BYTE)accumulator;
} else {
*op++ = (BYTE)(lastRun << ML_BITS);
}
memcpy(op, anchor, lastRun);
op += lastRun;
}
/* End */
return (int)(((char *)op) - dest);
}