private static uint ReverseCountPattern(byte *ip, byte *iLow, uint pattern) { byte *iStart = ip; while (ip >= iLow + 4) { if (LZ4MemoryHelper.Peek32(ip - 4) != pattern) { break; } ip -= 4; } { // works for any endianess byte *bytePtr = (byte *)&pattern + 3; while (ip > iLow) { if (ip[-1] != *bytePtr) { break; } ip--; bytePtr--; } } return((uint)(iStart - ip)); }
private static uint HashPosition(void *p, TableTypeT tableType) { #if !BIT32 if (tableType != TableTypeT.ByU16) { return(Hash5(ReadArch(p), tableType)); } #endif return(Hash4(LZ4MemoryHelper.Peek32(p), tableType)); }
protected static uint Count(byte *pIn, byte *pMatch, byte *pInLimit) { byte *pStart = pIn; if (pIn < pInLimit - (StepSize - 1)) { ulong diff = ReadArch(pMatch) ^ ReadArch(pIn); if (diff != 0) { return(NbCommonBytes(diff)); } pIn += StepSize; pMatch += StepSize; } while (pIn < pInLimit - (StepSize - 1)) { ulong diff = ReadArch(pMatch) ^ ReadArch(pIn); if (diff != 0) { return((uint)(pIn + NbCommonBytes(diff) - pStart)); } pIn += StepSize; pMatch += StepSize; } #if !BIT32 if ((pIn < pInLimit - 3) && (LZ4MemoryHelper.Peek32(pMatch) == LZ4MemoryHelper.Peek32(pIn))) { pIn += 4; pMatch += 4; } #endif if ((pIn < pInLimit - 1) && (LZ4MemoryHelper.Peek16(pMatch) == LZ4MemoryHelper.Peek16(pIn))) { pIn += 2; pMatch += 2; } if ((pIn < pInLimit) && (*pMatch == *pIn)) { pIn++; } return((uint)(pIn - pStart)); }
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 InsertAndGetWiderMatch(CCtxT *hc4, byte *ip, byte *iLowLimit, byte *iHighLimit, int longest, byte **matchpos, byte **startpos, int maxNbAttempts, int patternAnalysis) { ushort *chainTable = hc4->ChainTable; uint * hashTable = hc4->HashTable; byte * basep = hc4->BaseP; uint dictLimit = hc4->DictLimit; byte * lowPrefixPtr = basep + dictLimit; uint lowLimit = hc4->LowLimit + 64 * KB > (uint)(ip - basep) ? hc4->LowLimit : (uint)(ip - basep) - MaxDistance; byte * dictBase = hc4->DictBase; int delta = (int)(ip - iLowLimit); int nbAttempts = maxNbAttempts; uint pattern = LZ4MemoryHelper.Peek32(ip); RepeatStateE repeat = RepeatStateE.RepUntested; int srcPatternLength = 0; // First Match Insert(hc4, ip); uint matchIndex = hashTable[HashPtr(ip)]; while ((matchIndex >= lowLimit) && (nbAttempts != 0)) { nbAttempts--; if (matchIndex >= dictLimit) { byte *matchPtr = basep + matchIndex; if (*(iLowLimit + longest) == *(matchPtr - delta + longest)) { if (LZ4MemoryHelper.Peek32(matchPtr) == pattern) { int mlt = MinMatch + (int)Count(ip + MinMatch, matchPtr + MinMatch, iHighLimit); int back = 0; while ((ip + back > iLowLimit) && (matchPtr + back > lowPrefixPtr) && (ip[back - 1] == matchPtr[back - 1])) { back--; } mlt -= back; if (mlt > longest) { longest = mlt; *matchpos = matchPtr + back; *startpos = ip + back; } } } } else { byte *matchPtr = dictBase + matchIndex; if (LZ4MemoryHelper.Peek32(matchPtr) == pattern) { int back = 0; byte *vLimit = ip + (dictLimit - matchIndex); if (vLimit > iHighLimit) { vLimit = iHighLimit; } int mlt = MinMatch + (int)Count(ip + MinMatch, matchPtr + MinMatch, vLimit); if ((ip + mlt == vLimit) && (vLimit < iHighLimit)) { mlt += (int)Count(ip + mlt, basep + dictLimit, iHighLimit); } while ((ip + back > iLowLimit) && (matchIndex + back > lowLimit) && (ip[back - 1] == matchPtr[back - 1])) { back--; } mlt -= back; if (mlt > longest) { longest = mlt; *matchpos = basep + matchIndex + back; *startpos = ip + back; } } } { ushort nextOffset = DeltaNextU16(chainTable, (ushort)matchIndex); matchIndex -= nextOffset; if ((patternAnalysis != 0) && (nextOffset == 1)) { // may be a repeated pattern if (repeat == RepeatStateE.RepUntested) { if (((pattern & 0xFFFF) == pattern >> 16) & ((pattern & 0xFF) == pattern >> 24)) { repeat = RepeatStateE.RepConfirmed; srcPatternLength = (int)CountPattern(ip + 4, iHighLimit, pattern) + 4; } else { repeat = RepeatStateE.RepNot; } } if ((repeat == RepeatStateE.RepConfirmed) && (matchIndex >= dictLimit)) { byte *matchPtr = basep + matchIndex; if (LZ4MemoryHelper.Peek32(matchPtr) == pattern) { int forwardPatternLength = (int)CountPattern(matchPtr + sizeof(uint), iHighLimit, pattern) + sizeof(uint); byte *maxLowPtr = lowPrefixPtr + MaxDistance >= ip ? lowPrefixPtr : ip - MaxDistance; int backLength = (int)ReverseCountPattern(matchPtr, maxLowPtr, pattern); int currentSegmentLength = backLength + forwardPatternLength; if ((currentSegmentLength >= srcPatternLength) && (forwardPatternLength <= srcPatternLength)) { matchIndex += (uint)(forwardPatternLength - srcPatternLength); } else { matchIndex -= (uint)backLength; } } } } } } return(longest); }
private static uint HashPtr(void *ptr) { return((LZ4MemoryHelper.Peek32(ptr) * 2654435761U) >> (MinMatch * 8 - HashLogHC)); }