public static int LZ4_decompress_generic( byte *src, byte *dst, int srcSize, int outputSize, endCondition_directive endOnInput, earlyEnd_directive partialDecoding, int targetOutputSize, dict_directive dict, byte *lowPrefix, byte *dictStart, int dictSize) { var ip = src; var iend = ip + srcSize; var op = dst; var oend = op + outputSize; var oexit = op + targetOutputSize; var dictEnd = dictStart + dictSize; var safeDecode = endOnInput == endCondition_directive.endOnInputSize; var checkOffset = safeDecode && dictSize < 64 * KB; if (partialDecoding != earlyEnd_directive.full && oexit > oend - MFLIMIT) { oexit = oend - MFLIMIT; } if (endOnInput == endCondition_directive.endOnInputSize && outputSize == 0) { return(srcSize == 1 && *ip == 0 ? 0 : -1); } if (endOnInput != endCondition_directive.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 << ML_BITS && (token & ML_MASK) != 15) { var ll = (int)(token >> ML_BITS); int off = Mem.Peek16(ip + ll); var matchPtr = op + ll - off; if (off >= 18 && matchPtr >= lowPrefix) { var ml = (int)((token & ML_MASK) + MINMATCH); Mem.Copy16(op, ip); op += ll; ip += ll + 2; Mem.Copy18(op, matchPtr); op += ml; continue; } } if ((length = (int)(token >> ML_BITS)) == RUN_MASK) { uint s; do { s = *ip++; length += (int)s; }while ( (endOnInput != endCondition_directive.endOnInputSize || ip < iend - RUN_MASK) && s == 255); if (safeDecode && op + length < op) { goto _output_error; } if (safeDecode && ip + length < ip) { goto _output_error; } } var cpy = op + length; if (endOnInput == endCondition_directive.endOnInputSize && ( cpy > (partialDecoding == earlyEnd_directive.partial ? oexit : oend - MFLIMIT) || ip + length > iend - (2 + 1 + LASTLITERALS) ) || endOnInput != endCondition_directive.endOnInputSize && cpy > oend - WILDCOPYLENGTH) { if (partialDecoding == earlyEnd_directive.partial) { if (cpy > oend) { goto _output_error; } if (endOnInput == endCondition_directive.endOnInputSize && ip + length > iend) { goto _output_error; } } else { if (endOnInput != endCondition_directive.endOnInputSize && cpy != oend) { goto _output_error; } if (endOnInput == endCondition_directive.endOnInputSize && (ip + length != iend || cpy > oend)) { goto _output_error; } } Mem.Copy(op, ip, length); ip += length; op += length; break; } Mem.WildCopy(op, ip, cpy); ip += length; op = cpy; int offset = Mem.Peek16(ip); ip += 2; var match = op - offset; if (checkOffset && match + dictSize < lowPrefix) { goto _output_error; } Mem.Poke32(op, (uint)offset); length = (int)(token & ML_MASK); if (length == ML_MASK) { uint s; do { s = *ip++; if ((endOnInput == endCondition_directive.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 == dict_directive.usingExtDict && match < lowPrefix) { if (op + length > oend - LASTLITERALS) { goto _output_error; } if (length <= lowPrefix - match) { Mem.Move(op, dictEnd - (lowPrefix - match), length); op += length; } else { var copySize = (int)(lowPrefix - match); var restSize = length - copySize; Mem.Copy(op, dictEnd - copySize, copySize); op += copySize; if (restSize > (int)(op - lowPrefix)) { var endOfMatch = op + restSize; var copyFrom = lowPrefix; while (op < endOfMatch) { *op++ = *copyFrom++; } } else { Mem.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]; Mem.Copy(op + 4, match, 4); match -= dec64table[offset]; } else { Mem.Copy8(op, match); match += 8; } op += 8; if (cpy > oend - 12) { var oCopyLimit = oend - (WILDCOPYLENGTH - 1); if (cpy > oend - LASTLITERALS) { goto _output_error; } if (op < oCopyLimit) { Mem.WildCopy(op, match, oCopyLimit); match += oCopyLimit - op; op = oCopyLimit; } while (op < cpy) { *op++ = *match++; } } else { Mem.Copy8(op, match); if (length > 16) { Mem.WildCopy(op + 8, match + 8, cpy); } } op = cpy; /* correction */ } /* end of decoding */ if (endOnInput == endCondition_directive.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); }
public static int LZ4_compress_generic( LZ4_stream_t *cctx, byte *source, byte *dest, int inputSize, int maxOutputSize, limitedOutput_directive outputLimited, tableType_t tableType, dict_directive dict, dictIssue_directive dictIssue, uint acceleration) { var ip = source; byte *ibase; byte *lowLimit; var lowRefLimit = ip - cctx->dictSize; var dictionary = cctx->dictionary; var dictEnd = dictionary + cctx->dictSize; var dictDelta = dictEnd - source; var anchor = source; var iend = ip + inputSize; var mflimit = iend - MFLIMIT; var matchlimit = iend - LASTLITERALS; var op = dest; var olimit = op + maxOutputSize; if (inputSize > LZ4_MAX_INPUT_SIZE) { return(0); } switch (dict) { case dict_directive.withPrefix64k: ibase = source - cctx->currentOffset; lowLimit = source - cctx->dictSize; break; case dict_directive.usingExtDict: ibase = source - cctx->currentOffset; lowLimit = source; break; default: ibase = source; lowLimit = source; break; } if (tableType == tableType_t.byU16 && inputSize >= LZ4_64Klimit) { return(0); } if (inputSize < LZ4_minLength) { goto _last_literals; } LZ4_putPosition(ip, cctx->hashTable, tableType, ibase); ip++; var forwardH = LZ4_hashPosition(ip, tableType); for (; ;) { var refDelta = 0L; byte *match; byte *token; { var forwardIp = ip; var step = 1u; var searchMatchNb = acceleration << LZ4_skipTrigger; do { var h = forwardH; ip = forwardIp; forwardIp += step; step = searchMatchNb++ >> LZ4_skipTrigger; if (forwardIp > mflimit) { goto _last_literals; } match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, ibase); if (dict == dict_directive.usingExtDict) { if (match < source) { refDelta = dictDelta; lowLimit = dictionary; } else { refDelta = 0; lowLimit = source; } } forwardH = LZ4_hashPosition(forwardIp, tableType); LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, ibase); }while ( dictIssue == dictIssue_directive.dictSmall && match < lowRefLimit || tableType != tableType_t.byU16 && match + MAX_DISTANCE < ip || Mem.Peek32(match + refDelta) != Mem.Peek32(ip)); } while (ip > anchor && match + refDelta > lowLimit && ip[-1] == match[refDelta - 1]) { ip--; match--; } { var litLength = (uint)(ip - anchor); token = op++; if (outputLimited == limitedOutput_directive.limitedOutput && op + litLength + (2 + 1 + LASTLITERALS) + litLength / 255 > olimit) { return(0); } if (litLength >= RUN_MASK) { var len = (int)(litLength - RUN_MASK); *token = (byte)(RUN_MASK << ML_BITS); for (; len >= 255; len -= 255) { *op++ = 255; } *op++ = (byte)len; } else { *token = (byte)(litLength << ML_BITS); } Mem.WildCopy(op, anchor, op + litLength); op += litLength; } _next_match: Mem.Poke16(op, (ushort)(ip - match)); op += 2; { uint matchCode; if (dict == dict_directive.usingExtDict && lowLimit == dictionary) { match += refDelta; var limit = ip + (dictEnd - match); if (limit > matchlimit) { limit = matchlimit; } matchCode = LZ4_count(ip + MINMATCH, match + MINMATCH, limit); ip += MINMATCH + matchCode; if (ip == limit) { var more = LZ4_count(ip, source, matchlimit); matchCode += more; ip += more; } } else { matchCode = LZ4_count(ip + MINMATCH, match + MINMATCH, matchlimit); ip += MINMATCH + matchCode; } if (outputLimited == limitedOutput_directive.limitedOutput && op + (1 + LASTLITERALS) + (matchCode >> 8) > olimit) { return(0); } if (matchCode >= ML_MASK) { *token += (byte)ML_MASK; matchCode -= ML_MASK; Mem.Poke32(op, 0xFFFFFFFF); while (matchCode >= 4 * 255) { op += 4; Mem.Poke32(op, 0xFFFFFFFF); matchCode -= 4 * 255; } op += matchCode / 255; *op++ = (byte)(matchCode % 255); } else { *token += (byte)matchCode; } } anchor = ip; if (ip > mflimit) { break; } LZ4_putPosition(ip - 2, cctx->hashTable, tableType, ibase); match = LZ4_getPosition(ip, cctx->hashTable, tableType, ibase); if (dict == dict_directive.usingExtDict) { if (match < source) { refDelta = dictDelta; lowLimit = dictionary; } else { refDelta = 0; lowLimit = source; } } LZ4_putPosition(ip, cctx->hashTable, tableType, ibase); if ((dictIssue != dictIssue_directive.dictSmall || match >= lowRefLimit) && match + MAX_DISTANCE >= ip && Mem.Peek32(match + refDelta) == Mem.Peek32(ip)) { token = op++; *token = 0; goto _next_match; } forwardH = LZ4_hashPosition(++ip, tableType); } _last_literals: { var lastRun = (int)(iend - anchor); if (outputLimited == limitedOutput_directive.limitedOutput && op - dest + lastRun + 1 + (lastRun + 255 - RUN_MASK) / 255 > (uint)maxOutputSize) { return(0); } if (lastRun >= RUN_MASK) { var accumulator = (int)(lastRun - RUN_MASK); *op++ = (byte)(RUN_MASK << ML_BITS); for (; accumulator >= 255; accumulator -= 255) { *op++ = 255; } *op++ = (byte)accumulator; } else { *op++ = (byte)(lastRun << ML_BITS); } Mem.Copy(op, anchor, lastRun); op += lastRun; } return((int)(op - dest)); }