private static int CompressDestSizeGeneric(StreamT *ctx, byte *src, byte *dst, int *srcSizePtr, int targetDstSize, TableTypeT tableType) { byte *ip = src; byte *srcBase = src; byte *lowLimit = src; byte *anchor = ip; byte *iend = ip + *srcSizePtr; byte *mflimit = iend - MFLimit; byte *matchlimit = iend - LastLiterals; byte *op = dst; byte *oend = op + targetDstSize; byte *oMaxLit = op + targetDstSize - 2 - 8 - 1; byte *oMaxMatch = op + targetDstSize - (LastLiterals + 1); byte *oMaxSeq = oMaxLit - 1; if (targetDstSize < 1) { return(0); } if (*srcSizePtr > MaxInputSize) { return(0); } if ((tableType == TableTypeT.ByU16) && (*srcSizePtr >= Limit64k)) { return(0); } if (*srcSizePtr < LZ4MinLength) { goto _last_literals; // Input too small, no compression (all literals) } *srcSizePtr = 0; PutPosition(ip, ctx->HashTable, tableType, srcBase); ip++; uint forwardH = HashPosition(ip, tableType); for (; ;) { byte *match; byte *token; { byte *forwardIp = ip; uint step = 1u; uint searchMatchNb = 1u << SkipTrigger; do { uint h = forwardH; ip = forwardIp; forwardIp += step; step = searchMatchNb++ >> SkipTrigger; if (forwardIp > mflimit) { goto _last_literals; } match = GetPositionOnHash(h, ctx->HashTable, tableType, srcBase); forwardH = HashPosition(forwardIp, tableType); PutPositionOnHash(ip, h, ctx->HashTable, tableType, srcBase); }while ((tableType != TableTypeT.ByU16) && (match + MaxDistance < ip) || (LZ4MemoryHelper.Peek32(match) != LZ4MemoryHelper.Peek32(ip))); } while ((ip > anchor) && (match > lowLimit) && (ip[-1] == match[-1])) { ip--; match--; } { uint litLength = (uint)(ip - anchor); token = op++; if (op + (litLength + 240) / 255 + litLength > oMaxLit) { op--; goto _last_literals; } if (litLength >= RunMask) { uint len = litLength - RunMask; *token = (byte)(RunMask << MLBits); for (; len >= 255; len -= 255) { *op++ = 255; } *op++ = (byte)len; } else { *token = (byte)(litLength << MLBits); } LZ4MemoryHelper.WildCopy(op, anchor, op + litLength); op += litLength; } _next_match: LZ4MemoryHelper.Poke16(op, (ushort)(ip - match)); op += 2; { int matchLength = (int)Count(ip + MinMatch, match + MinMatch, matchlimit); if (op + (matchLength + 240) / 255 > oMaxMatch) { matchLength = (int)(15 - 1 + (oMaxMatch - op) * 255); } ip += MinMatch + matchLength; if (matchLength >= MLMask) { *token += (byte)MLMask; matchLength -= (int)MLMask; while (matchLength >= 255) { matchLength -= 255; *op++ = 255; } *op++ = (byte)matchLength; } else { *token += (byte)matchLength; } } anchor = ip; if (ip > mflimit) { break; } if (op > oMaxSeq) { break; } PutPosition(ip - 2, ctx->HashTable, tableType, srcBase); match = GetPosition(ip, ctx->HashTable, tableType, srcBase); PutPosition(ip, ctx->HashTable, tableType, srcBase); if ((match + MaxDistance >= ip) && (LZ4MemoryHelper.Peek32(match) == LZ4MemoryHelper.Peek32(ip))) { token = op++; *token = 0; goto _next_match; } forwardH = HashPosition(++ip, tableType); } _last_literals: { int lastRunSize = (int)(iend - anchor); if (op + 1 + (lastRunSize + 240) / 255 + lastRunSize > oend) { lastRunSize = (int)(oend - op) - 1; lastRunSize -= (lastRunSize + 240) / 255; } ip = anchor + lastRunSize; if (lastRunSize >= RunMask) { long accumulator = lastRunSize - RunMask; *op++ = (byte)(RunMask << MLBits); for (; accumulator >= 255; accumulator -= 255) { *op++ = 255; } *op++ = (byte)accumulator; } else { *op++ = (byte)(lastRunSize << MLBits); } LZ4MemoryHelper.Copy(op, anchor, lastRunSize); op += lastRunSize; } *srcSizePtr = (int)(ip - src); return((int)(op - dst)); }
public static int CompressGeneric(StreamT *cctx, byte *source, byte *dest, int inputSize, int maxOutputSize, LimitedOutputDirective outputLimited, TableTypeT tableType, DictDirective dict, DictIssueDirective dictIssue, uint acceleration) { byte *ip = source; byte *ibase; byte *lowLimit; byte *lowRefLimit = ip - cctx->DictSize; byte *dictionary = cctx->Dictionary; byte *dictEnd = dictionary + cctx->DictSize; long dictDelta = dictEnd - source; byte *anchor = source; byte *iend = ip + inputSize; byte *mflimit = iend - MFLimit; byte *matchlimit = iend - LastLiterals; byte *op = dest; byte *olimit = op + maxOutputSize; if (inputSize > MaxInputSize) { return(0); } switch (dict) { case DictDirective.WithPrefix64k: ibase = source - cctx->CurrentOffset; lowLimit = source - cctx->DictSize; break; case DictDirective.UsingExtDict: ibase = source - cctx->CurrentOffset; lowLimit = source; break; default: ibase = source; lowLimit = source; break; } if ((tableType == TableTypeT.ByU16) && (inputSize >= Limit64k)) { return(0); } if (inputSize < LZ4MinLength) { goto _last_literals; } PutPosition(ip, cctx->HashTable, tableType, ibase); ip++; uint forwardH = HashPosition(ip, tableType); for (; ;) { long refDelta = 0L; byte *match; byte *token; { byte *forwardIp = ip; uint step = 1u; uint searchMatchNb = acceleration << SkipTrigger; do { uint h = forwardH; ip = forwardIp; forwardIp += step; step = searchMatchNb++ >> SkipTrigger; if (forwardIp > mflimit) { goto _last_literals; } match = GetPositionOnHash(h, cctx->HashTable, tableType, ibase); if (dict == DictDirective.UsingExtDict) { if (match < source) { refDelta = dictDelta; lowLimit = dictionary; } else { refDelta = 0; lowLimit = source; } } forwardH = HashPosition(forwardIp, tableType); PutPositionOnHash(ip, h, cctx->HashTable, tableType, ibase); }while ((dictIssue == DictIssueDirective.DictSmall) && (match < lowRefLimit) || (tableType != TableTypeT.ByU16) && (match + MaxDistance < ip) || (LZ4MemoryHelper.Peek32(match + refDelta) != LZ4MemoryHelper.Peek32(ip))); } while ((ip > anchor) && (match + refDelta > lowLimit) && (ip[-1] == match[refDelta - 1])) { ip--; match--; } { uint litLength = (uint)(ip - anchor); token = op++; if ((outputLimited == LimitedOutputDirective.LimitedOutput) && (op + litLength + (2 + 1 + LastLiterals) + litLength / 255 > olimit)) { return(0); } if (litLength >= RunMask) { int len = (int)(litLength - RunMask); *token = (byte)(RunMask << MLBits); for (; len >= 255; len -= 255) { *op++ = 255; } *op++ = (byte)len; } else { *token = (byte)(litLength << MLBits); } LZ4MemoryHelper.WildCopy(op, anchor, op + litLength); op += litLength; } _next_match: LZ4MemoryHelper.Poke16(op, (ushort)(ip - match)); op += 2; { uint matchCode; if ((dict == DictDirective.UsingExtDict) && (lowLimit == dictionary)) { match += refDelta; byte *limit = ip + (dictEnd - match); if (limit > matchlimit) { limit = matchlimit; } matchCode = Count(ip + MinMatch, match + MinMatch, limit); ip += MinMatch + matchCode; if (ip == limit) { uint more = Count(ip, source, matchlimit); matchCode += more; ip += more; } } else { matchCode = Count(ip + MinMatch, match + MinMatch, matchlimit); ip += MinMatch + matchCode; } if ((outputLimited == LimitedOutputDirective.LimitedOutput) && (op + (1 + LastLiterals) + (matchCode >> 8) > olimit)) { return(0); } if (matchCode >= MLMask) { *token += (byte)MLMask; matchCode -= MLMask; LZ4MemoryHelper.Poke32(op, 0xFFFFFFFF); while (matchCode >= 4 * 255) { op += 4; LZ4MemoryHelper.Poke32(op, 0xFFFFFFFF); matchCode -= 4 * 255; } op += matchCode / 255; *op++ = (byte)(matchCode % 255); } else { *token += (byte)matchCode; } } anchor = ip; if (ip > mflimit) { break; } PutPosition(ip - 2, cctx->HashTable, tableType, ibase); match = GetPosition(ip, cctx->HashTable, tableType, ibase); if (dict == DictDirective.UsingExtDict) { if (match < source) { refDelta = dictDelta; lowLimit = dictionary; } else { refDelta = 0; lowLimit = source; } } PutPosition(ip, cctx->HashTable, tableType, ibase); if ((dictIssue != DictIssueDirective.DictSmall || match >= lowRefLimit) && (match + MaxDistance >= ip) && (LZ4MemoryHelper.Peek32(match + refDelta) == LZ4MemoryHelper.Peek32(ip))) { token = op++; *token = 0; goto _next_match; } forwardH = HashPosition(++ip, tableType); } _last_literals: { int lastRun = (int)(iend - anchor); if ((outputLimited == LimitedOutputDirective.LimitedOutput) && (op - dest + lastRun + 1 + (lastRun + 255 - RunMask) / 255 > (uint)maxOutputSize)) { return(0); } if (lastRun >= RunMask) { int accumulator = (int)(lastRun - RunMask); *op++ = (byte)(RunMask << MLBits); for (; accumulator >= 255; accumulator -= 255) { *op++ = 255; } *op++ = (byte)accumulator; } else { *op++ = (byte)(lastRun << MLBits); } LZ4MemoryHelper.Copy(op, anchor, lastRun); op += lastRun; } return((int)(op - dest)); }
private static int CompressHashChain(CCtxT *ctx, byte *source, byte *dest, int *srcSizePtr, int maxOutputSize, uint maxNbAttempts, LimitedOutputDirective limit) { int inputSize = *srcSizePtr; int patternAnalysis = maxNbAttempts > 64 ? 1 : 0; // levels 8+ byte *ip = source; byte *anchor = ip; byte *iend = ip + inputSize; byte *mflimit = iend - MFLimit; byte *matchlimit = (iend - LastLiterals); byte *optr; byte *op = dest; byte *oend = op + maxOutputSize; byte *refPos = null; byte *start2 = null; byte *ref2 = null; byte *start3 = null; byte *ref3 = null; // init *srcSizePtr = 0; if (limit == LimitedOutputDirective.LimitedDestSize) { oend -= LastLiterals; // Hack for support LZ4 format restriction } if (inputSize < LZ4MinLength) { goto _last_literals; // Input too small, no compression (all literals) } // Main Loop while (ip < mflimit) { int ml = InsertAndFindBestMatch( ctx, ip, matchlimit, &refPos, (int)maxNbAttempts, patternAnalysis); if (ml < MinMatch) { ip++; continue; } // saved, in case we would skip too much byte *start0 = ip; byte *ref0 = refPos; int ml0 = ml; _Search2: int ml2; if (ip + ml < mflimit) { ml2 = InsertAndGetWiderMatch( ctx, ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2, (int)maxNbAttempts, patternAnalysis); } else { ml2 = ml; } if (ml2 == ml) { // No better match optr = op; if (EncodeSequence(&ip, &op, &anchor, ml, refPos, limit, oend) != 0) { goto _dest_overflow; } continue; } if (start0 < ip) { if (start2 < ip + ml0) { // empirical ip = start0; refPos = ref0; ml = ml0; } } // Here, start0==ip if (start2 - ip < 3) { // First Match too small : removed ml = ml2; ip = start2; refPos = ref2; goto _Search2; } _Search3: // At this stage, we have : // ml2 > ml1, and // ip1+3 <= ip2 (usually < ip1+ml1) if ((start2 - ip) < OptimalML) { int newMl = ml; if (newMl > OptimalML) { newMl = OptimalML; } if (ip + newMl > start2 + ml2 - MinMatch) { newMl = (int)(start2 - ip) + ml2 - MinMatch; } int correction = newMl - (int)(start2 - ip); if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; } } // Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) int ml3; if (start2 + ml2 < mflimit) { ml3 = InsertAndGetWiderMatch( ctx, start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3, (int)maxNbAttempts, patternAnalysis); } else { ml3 = ml2; } if (ml3 == ml2) { // No better match : 2 sequences to encode // ip & ref are known; Now for ml if (start2 < ip + ml) { ml = (int)(start2 - ip); } // Now, encode 2 sequences optr = op; if (EncodeSequence(&ip, &op, &anchor, ml, refPos, limit, oend) != 0) { goto _dest_overflow; } ip = start2; optr = op; if (EncodeSequence(&ip, &op, &anchor, ml2, ref2, limit, oend) != 0) { goto _dest_overflow; } continue; } if (start3 < ip + ml + 3) { // Not enough space for match 2 : remove it if (start3 >= (ip + ml)) { // can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 if (start2 < ip + ml) { int correction = (int)(ip + ml - start2); start2 += correction; ref2 += correction; ml2 -= correction; if (ml2 < MinMatch) { start2 = start3; ref2 = ref3; ml2 = ml3; } } optr = op; if (EncodeSequence(&ip, &op, &anchor, ml, refPos, limit, oend) != 0) { goto _dest_overflow; } ip = start3; refPos = ref3; ml = ml3; start0 = start2; ref0 = ref2; ml0 = ml2; goto _Search2; } start2 = start3; ref2 = ref3; ml2 = ml3; goto _Search3; } // OK, now we have 3 ascending matches; let's write at least the first one // ip & ref are known; Now for ml if (start2 < ip + ml) { if (start2 - ip < (int)MLMask) { if (ml > OptimalML) { ml = OptimalML; } if (ip + ml > start2 + ml2 - MinMatch) { ml = (int)(start2 - ip) + ml2 - MinMatch; } int correction = ml - (int)(start2 - ip); if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; } } else { ml = (int)(start2 - ip); } } optr = op; if (EncodeSequence(&ip, &op, &anchor, ml, refPos, limit, oend) != 0) { goto _dest_overflow; } ip = start2; refPos = ref2; ml = ml2; start2 = start3; ref2 = ref3; ml2 = ml3; goto _Search3; } _last_literals: // Encode last literals { size_t lastRunSize = (size_t)(iend - anchor); // literals size_t litLength = (lastRunSize + 255 - RunMask) / 255; size_t totalSize = 1 + litLength + lastRunSize; if (limit == LimitedOutputDirective.LimitedDestSize) { oend += LastLiterals; // restore correct value } if ((limit != 0) && (op + totalSize > oend)) { if (limit == LimitedOutputDirective.LimitedOutput) { return(0); // Check output limit } // adapt lastRunSize to fill 'dest' lastRunSize = (size_t)(oend - op) - 1; litLength = (lastRunSize + 255 - RunMask) / 255; lastRunSize -= litLength; } ip = anchor + lastRunSize; if (lastRunSize >= RunMask) { size_t accumulator = lastRunSize - RunMask; *op++ = (byte)(RunMask << MLBits); for (; accumulator >= 255; accumulator -= 255) { *op++ = 255; } *op++ = (byte)accumulator; } else { *op++ = (byte)(lastRunSize << MLBits); } LZ4MemoryHelper.Copy(op, anchor, (int)lastRunSize); op += lastRunSize; } // End *srcSizePtr = (int)(ip - source); return((int)(op - dest)); _dest_overflow: if (limit != LimitedOutputDirective.LimitedDestSize) { return(0); } op = optr; // restore correct out pointer goto _last_literals; }
public static int DecompressGeneric(byte *src, byte *dst, int srcSize, int outputSize, EndConditionDirective endOnInput, EarlyEndDirective partialDecoding, int targetOutputSize, DictDirective dict, byte *lowPrefix, byte *dictStart, int dictSize) { byte *ip = src; byte *iend = ip + srcSize; byte *op = dst; byte *oend = op + outputSize; byte *oexit = op + targetOutputSize; byte *dictEnd = dictStart + dictSize; bool safeDecode = endOnInput == EndConditionDirective.EndOnInputSize; bool checkOffset = safeDecode && dictSize < 64 * KB; if ((partialDecoding != EarlyEndDirective.Full) && (oexit > oend - MFLimit)) { oexit = oend - MFLimit; } if ((endOnInput == EndConditionDirective.EndOnInputSize) && (outputSize == 0)) { return(srcSize == 1 && *ip == 0 ? 0 : -1); } if ((endOnInput != EndConditionDirective.EndOnInputSize) && (outputSize == 0)) { return(*ip == 0 ? 1 : -1); } for (; ;) { int length; uint token = *ip++; if ((ip + 14 + 2 <= iend) && (op + 14 + 18 <= oend) && (token < 15 << MLBits) && ((token & MLMask) != 15)) { int ll = (int)(token >> MLBits); int off = LZ4MemoryHelper.Peek16(ip + ll); byte *matchPtr = op + ll - off; if (off >= 18 && matchPtr >= lowPrefix) { int ml = (int)((token & MLMask) + MinMatch); LZ4MemoryHelper.Copy16(op, ip); op += ll; ip += ll + 2; LZ4MemoryHelper.Copy18(op, matchPtr); op += ml; continue; } } if ((length = (int)(token >> MLBits)) == RunMask) { uint s; do { s = *ip++; length += (int)s; }while ( (endOnInput != EndConditionDirective.EndOnInputSize || ip < iend - RunMask) && (s == 255)); if (safeDecode && op + length < op) { goto _output_error; } if (safeDecode && ip + length < ip) { goto _output_error; } } byte *cpy = op + length; if ((endOnInput == EndConditionDirective.EndOnInputSize) && ((cpy > (partialDecoding == EarlyEndDirective.Partial ? oexit : oend - MFLimit)) || (ip + length > iend - (2 + 1 + LastLiterals))) || (endOnInput != EndConditionDirective.EndOnInputSize) && (cpy > oend - WildCopyLength)) { if (partialDecoding == EarlyEndDirective.Partial) { if (cpy > oend) { goto _output_error; } if ((endOnInput == EndConditionDirective.EndOnInputSize) && (ip + length > iend)) { goto _output_error; } } else { if ((endOnInput != EndConditionDirective.EndOnInputSize) && (cpy != oend)) { goto _output_error; } if ((endOnInput == EndConditionDirective.EndOnInputSize) && (ip + length != iend || cpy > oend)) { goto _output_error; } } LZ4MemoryHelper.Copy(op, ip, length); ip += length; op += length; break; } LZ4MemoryHelper.WildCopy(op, ip, cpy); ip += length; op = cpy; int offset = LZ4MemoryHelper.Peek16(ip); ip += 2; byte *match = op - offset; if (checkOffset && match + dictSize < lowPrefix) { goto _output_error; } LZ4MemoryHelper.Poke32(op, (uint)offset); length = (int)(token & MLMask); if (length == MLMask) { uint s; do { s = *ip++; if ((endOnInput == EndConditionDirective.EndOnInputSize) && (ip > iend - LastLiterals)) { goto _output_error; } length += (int)s; }while (s == 255); if (safeDecode && (op + length < op)) { goto _output_error; } } length += MinMatch; if ((dict == DictDirective.UsingExtDict) && (match < lowPrefix)) { if (op + length > oend - LastLiterals) { goto _output_error; } if (length <= lowPrefix - match) { LZ4MemoryHelper.Move(op, dictEnd - (lowPrefix - match), length); op += length; } else { int copySize = (int)(lowPrefix - match); int restSize = length - copySize; LZ4MemoryHelper.Copy(op, dictEnd - copySize, copySize); op += copySize; if (restSize > (int)(op - lowPrefix)) { byte *endOfMatch = op + restSize; byte *copyFrom = lowPrefix; while (op < endOfMatch) { *op++ = *copyFrom++; } } else { LZ4MemoryHelper.Copy(op, lowPrefix, restSize); op += restSize; } } continue; } cpy = op + length; if (offset < 8) { op[0] = match[0]; op[1] = match[1]; op[2] = match[2]; op[3] = match[3]; match += _inc32table[offset]; LZ4MemoryHelper.Copy(op + 4, match, 4); match -= _dec64table[offset]; } else { LZ4MemoryHelper.Copy8(op, match); match += 8; } op += 8; if (cpy > oend - 12) { byte *oCopyLimit = oend - (WildCopyLength - 1); if (cpy > oend - LastLiterals) { goto _output_error; } if (op < oCopyLimit) { LZ4MemoryHelper.WildCopy(op, match, oCopyLimit); match += oCopyLimit - op; op = oCopyLimit; } while (op < cpy) { *op++ = *match++; } } else { LZ4MemoryHelper.Copy8(op, match); if (length > 16) { LZ4MemoryHelper.WildCopy(op + 8, match + 8, cpy); } } op = cpy; // correction } // end of decoding if (endOnInput == EndConditionDirective.EndOnInputSize) { return((int)(op - dst)); // Nb of output bytes decoded } return((int)(ip - src)); // Nb of input bytes read // Overflow error detected _output_error: return((int)-(ip - src) - 1); }
// ----------------------------------------------------------------- private static int CompressOptimal(CCtxT *ctx, byte *source, byte *dst, int *srcSizePtr, int dstCapacity, int nbSearches, size_t sufficientLen, LimitedOutputDirective limit, int fullUpdate) { const int TrailingLiterals = 3; OptimalT *opt = stackalloc OptimalT[OptNum + TrailingLiterals]; byte *ip = source; byte *anchor = ip; byte *iend = ip + *srcSizePtr; byte *mflimit = iend - MFLimit; byte *matchlimit = iend - LastLiterals; byte *op = dst; byte *opSaved; byte *oend = op + dstCapacity; *srcSizePtr = 0; if (limit == LimitedOutputDirective.LimitedDestSize) { oend -= LastLiterals; } if (sufficientLen >= OptNum) { sufficientLen = OptNum - 1; } // Main Loop while (ip < mflimit) { int llen = (int)(ip - anchor); int bestMlen, bestOff; int cur, lastMatchPos; MatchT firstMatch = FindLongerMatch(ctx, ip, matchlimit, MinMatch - 1, nbSearches); if (firstMatch.Len == 0) { ip++; continue; } if ((size_t)firstMatch.Len > sufficientLen) { int firstML = firstMatch.Len; byte *matchPos = ip - firstMatch.Off; opSaved = op; if (EncodeSequence(&ip, &op, &anchor, firstML, matchPos, limit, oend) != 0) { goto _dest_overflow; } continue; } // set prices for first positions (literals) { int rPos; for (rPos = 0; rPos < MinMatch; rPos++) { int cost = LiteralsPrice(llen + rPos); opt[rPos].Mlen = 1; opt[rPos].Off = 0; opt[rPos].Litlen = llen + rPos; opt[rPos].Price = cost; } } // set prices using initial match { int mlen = MinMatch; int matchML = firstMatch.Len; // necessarily < sufficient_len < LZ4_OPT_NUM int offset = firstMatch.Off; for (; mlen <= matchML; mlen++) { int cost = SequencePrice(llen, mlen); opt[mlen].Mlen = mlen; opt[mlen].Off = offset; opt[mlen].Litlen = llen; opt[mlen].Price = cost; } } lastMatchPos = firstMatch.Len; { int addLit; for (addLit = 1; addLit <= TrailingLiterals; addLit++) { opt[lastMatchPos + addLit].Mlen = 1; opt[lastMatchPos + addLit].Off = 0; opt[lastMatchPos + addLit].Litlen = addLit; opt[lastMatchPos + addLit].Price = opt[lastMatchPos].Price + LiteralsPrice(addLit); } } // check further positions for (cur = 1; cur < lastMatchPos; cur++) { byte *curPtr = ip + cur; if (curPtr >= mflimit) { break; } if (fullUpdate != 0) { if ((opt[cur + 1].Price <= opt[cur].Price) && (opt[cur + MinMatch].Price < opt[cur].Price + 3)) { continue; } } else { if (opt[cur + 1].Price <= opt[cur].Price) { continue; } } MatchT newMatch = FindLongerMatch( ctx, curPtr, matchlimit, fullUpdate != 0 ? MinMatch - 1 : lastMatchPos - cur, nbSearches); if (newMatch.Len == 0) { continue; } if ((size_t)newMatch.Len > sufficientLen || newMatch.Len + cur >= OptNum) { // immediate encoding bestMlen = newMatch.Len; bestOff = newMatch.Off; lastMatchPos = cur + 1; goto encode; } // before match : set price with literals at beginning { int baseLitlen = opt[cur].Litlen; for (int litlen = 1; litlen < MinMatch; litlen++) { int price = opt[cur].Price - LiteralsPrice(baseLitlen) + LiteralsPrice(baseLitlen + litlen); int pos = cur + litlen; if (price >= opt[pos].Price) { continue; } opt[pos].Mlen = 1; opt[pos].Off = 0; opt[pos].Litlen = baseLitlen + litlen; opt[pos].Price = price; } } // set prices using match at position = cur { int matchML = newMatch.Len; int ml = MinMatch; for (; ml <= matchML; ml++) { int pos = cur + ml; int offset = newMatch.Off; int price; int ll; if (opt[cur].Mlen == 1) { ll = opt[cur].Litlen; price = ((cur > ll) ? opt[cur - ll].Price : 0) + SequencePrice(ll, ml); } else { ll = 0; price = opt[cur].Price + SequencePrice(0, ml); } if ((pos > lastMatchPos + TrailingLiterals) || (price <= opt[pos].Price)) { if (ml == matchML && lastMatchPos < pos) { lastMatchPos = pos; } opt[pos].Mlen = ml; opt[pos].Off = offset; opt[pos].Litlen = ll; opt[pos].Price = price; } } } { int addLit; for (addLit = 1; addLit <= TrailingLiterals; addLit++) { opt[lastMatchPos + addLit].Mlen = 1; opt[lastMatchPos + addLit].Off = 0; opt[lastMatchPos + addLit].Litlen = addLit; opt[lastMatchPos + addLit].Price = opt[lastMatchPos].Price + LiteralsPrice(addLit); } } } bestMlen = opt[lastMatchPos].Mlen; bestOff = opt[lastMatchPos].Off; cur = lastMatchPos - bestMlen; encode: // cur, last_match_pos, best_mlen, best_off must be set { int candidate_pos = cur; int selected_matchLength = bestMlen; int selected_offset = bestOff; while (true) { int next_matchLength = opt[candidate_pos].Mlen; int next_offset = opt[candidate_pos].Off; 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; } candidate_pos -= next_matchLength; } } { int rPos = 0; while (rPos < lastMatchPos) { int ml = opt[rPos].Mlen; int offset = opt[rPos].Off; if (ml == 1) { ip++; rPos++; continue; } rPos += ml; opSaved = op; if (EncodeSequence(&ip, &op, &anchor, ml, ip - offset, limit, oend) != 0) { goto _dest_overflow; } } } } _last_literals: { size_t lastRunSize = (size_t)(iend - anchor); size_t litLength = (lastRunSize + 255 - RunMask) / 255; size_t totalSize = 1 + litLength + lastRunSize; if (limit == LimitedOutputDirective.LimitedDestSize) { oend += LastLiterals; } if (limit != 0 && op + totalSize > oend) { if (limit == LimitedOutputDirective.LimitedOutput) { return(0); } lastRunSize = (size_t)(oend - op) - 1; litLength = (lastRunSize + 255 - RunMask) / 255; lastRunSize -= litLength; } ip = anchor + lastRunSize; if (lastRunSize >= RunMask) { size_t accumulator = lastRunSize - RunMask; * op++ = (byte)(RunMask << MLBits); for (; accumulator >= 255; accumulator -= 255) { *op++ = 255; } *op++ = (byte)accumulator; } else { *op++ = (byte)(lastRunSize << MLBits); } LZ4MemoryHelper.Copy(op, anchor, (int)lastRunSize); op += lastRunSize; } // End *srcSizePtr = (int)(ip - source); return((int)(op - dst)); _dest_overflow: if (limit != LimitedOutputDirective.LimitedDestSize) { return(0); } op = opSaved; // restore correct out pointer goto _last_literals; }