private static void LZ4_putPosition <TTableType>(byte *p, Lz4StreamTInternal *ctx, byte *srcBase) where TTableType : ITableTypeDirective { int h = LZ4_hashPosition <TTableType>(p); LZ4_putPositionOnHash <TTableType>(p, h, ctx, srcBase); }
private static byte *LZ4_getPosition <TTableType>(byte *p, Lz4StreamTInternal *ctx, byte *srcBase) where TTableType : ITableTypeDirective { int h = LZ4_hashPosition <TTableType>(p); return(LZ4_getPositionOnHash <TTableType>(h, ctx, srcBase)); }
private static byte *LZ4_getPositionOnHash <TTableType>(int h, Lz4StreamTInternal *ctx, byte *srcBase) where TTableType : ITableTypeDirective { if (typeof(TTableType) == typeof(ByU32)) { return(srcBase + ctx->hashTable[h]); } else if (typeof(TTableType) == typeof(ByU16)) { return(srcBase + ((ushort *)ctx->hashTable)[h]); } ThrowException(new NotSupportedException("TTableType directive is not supported.")); return(default(byte *)); }
private static void LZ4_putPositionOnHash <TTableType>(byte *p, int h, Lz4StreamTInternal *ctx, byte *srcBase) where TTableType : ITableTypeDirective { if (typeof(TTableType) == typeof(ByU32)) { ctx->hashTable[h] = (int)(p - srcBase); } else if (typeof(TTableType) == typeof(ByU16)) { ((ushort *)ctx->hashTable)[h] = (ushort)(p - srcBase); } else { ThrowException(new NotSupportedException("TTableType directive is not supported.")); } }
private static int LZ4_compress_generic <TLimited, TTableType, TDictionaryType, TDictionaryIssue>(Lz4StreamTInternal *dictPtr, ref byte *source, ref byte *dest, int inputSize, int maxOutputSize, int acceleration) where TLimited : ILimitedOutputDirective where TTableType : ITableTypeDirective where TDictionaryType : IDictionaryTypeDirective where TDictionaryIssue : IDictionaryIssueDirective { Lz4StreamTInternal *ctx = dictPtr; byte *op = dest; byte *ip = source; byte *anchor = source; byte *dictionary = ctx->dictionary; byte *dictEnd = dictionary + ctx->dictSize; byte *lowRefLimit = ip - ctx->dictSize; long dictDelta = (long)dictEnd - (long)source; byte *iend = ip + inputSize; byte *mflimit = iend - MFLIMIT; byte *matchlimit = iend - LASTLITERALS; byte *olimit = op + maxOutputSize; // Init conditions if (typeof(TLimited) == typeof(LimitedDestSize) && maxOutputSize < 1) { return(0); /* Impossible to store anything */ } if (inputSize > LZ4_MAX_INPUT_SIZE) { return(0); // Unsupported input size, too large (or negative) } byte * @base; byte * lowLimit; if (typeof(TDictionaryType) == typeof(NoDict)) { @base = source; lowLimit = source; } else if (typeof(TDictionaryType) == typeof(WithPrefix64K)) { @base = source - ctx->currentOffset; lowLimit = source - ctx->dictSize; } else if (typeof(TDictionaryType) == typeof(UsingExtDict)) { @base = source - ctx->currentOffset; lowLimit = source; } else { throw new NotSupportedException("Unsupported IDictionaryTypeDirective."); } if ((typeof(TTableType) == typeof(ByU16)) && (inputSize >= LZ4_64_KLIMIT)) // Size too large (not within 64K limit) { return(0); } if (inputSize < LZ4_MIN_LENGTH) // Input too small, no compression (all literals) { goto _last_literals; } // First Byte LZ4_putPosition <TTableType>(ip, ctx, @base); ip++; int forwardH = LZ4_hashPosition <TTableType>(ip); // Main Loop long refDelta = 0; for (;;) { byte *match; { byte *forwardIp = ip; int step = 1; int searchMatchNb = acceleration << LZ4_SKIP_TRIGGER; do { int h = forwardH; ip = forwardIp; forwardIp += step; step = (searchMatchNb++ >> LZ4_SKIP_TRIGGER); if (forwardIp > mflimit) { goto _last_literals; } match = LZ4_getPositionOnHash <TTableType>(h, ctx, @base); if (typeof(TDictionaryType) == typeof(UsingExtDict)) { if (match < source) { refDelta = dictDelta; lowLimit = dictionary; } else { refDelta = 0; lowLimit = source; } } if (typeof(TTableType) == typeof(ByU16)) { ulong value = *((ulong *)forwardIp) * PRIME5_BYTES >> (40 - BY_U16_HASH_LOG); forwardH = (int)(value & BY_U16_HASH_MASK); ((ushort *)ctx->hashTable)[h] = (ushort)(ip - @base); } else if (typeof(TTableType) == typeof(ByU32)) { ulong value = (*((ulong *)forwardIp) * PRIME5_BYTES >> (40 - BY_U32_HASH_LOG)); forwardH = (int)(value & BY_U32_HASH_MASK); ctx->hashTable[h] = (int)(ip - @base); } else { throw new NotSupportedException("TTableType directive is not supported."); } }while (((typeof(TDictionaryType) == typeof(DictSmall)) ? (match < lowRefLimit) : false) || ((typeof(TTableType) == typeof(ByU16)) ? false : (match + MAX_DISTANCE < ip)) || (*(uint *)(match + refDelta) != *((uint *)ip))); } // Catch up while ((ip > anchor) && (match + refDelta > lowLimit) && (ip[-1] == match[refDelta - 1])) { ip--; match--; } // Encode Literal length byte *token; { int litLength = (int)(ip - anchor); token = op++; /* Check output limit */ if ((typeof(TLimited) == typeof(LimitedOutput)) && (op + litLength + (litLength / 255) + sizeof(ushort) > olimit)) { op = token; ip = anchor; goto _skip_last_literals; } if (litLength >= RUN_MASK) { int len = 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 */ WildCopy(op, anchor, (op + litLength)); op += litLength; } _next_match: // Encode Offset *((ushort *)op) = (ushort)(ip - match); op += sizeof(ushort); // Encode MatchLength { int matchLength; if ((typeof(TDictionaryType) == typeof(UsingExtDict)) && (lowLimit == dictionary)) { match += refDelta; byte *limit = ip + (dictEnd - match); if (limit > matchlimit) { limit = matchlimit; } matchLength = LZ4_count(ip + MINMATCH, match + MINMATCH, limit); ip += MINMATCH + matchLength; if (ip == limit) { int more = LZ4_count(ip, source, matchlimit); matchLength += more; ip += more; } } else { matchLength = LZ4_count(ip + MINMATCH, match + MINMATCH, matchlimit); ip += MINMATCH + matchLength; } if ((typeof(TLimited) == typeof(LimitedOutput)) && ((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) { *(ushort *)op = (255 << 8 | 255); op += sizeof(ushort); } 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 <TTableType>(ip - 2, ctx, @base); /* Test next position */ match = LZ4_getPosition <TTableType>(ip, ctx, @base); if (typeof(TDictionaryType) == typeof(UsingExtDict)) { if (match < source) { refDelta = dictDelta; lowLimit = dictionary; } else { refDelta = 0; lowLimit = source; } } LZ4_putPosition <TTableType>(ip, ctx, @base); if (((typeof(TDictionaryType) == typeof(DictSmall)) ? (match >= lowRefLimit) : true) && (match + MAX_DISTANCE >= ip) && (*(uint *)(match + refDelta) == *(uint *)(ip))) { token = op++; *token = 0; goto _next_match; } /* Prepare next loop */ forwardH = LZ4_hashPosition <TTableType>(++ip); } _last_literals: /* Encode Last Literals */ { int lastRun = typeof(TLimited) == typeof(LimitedOutput) ? maxOutputSize - (int)(op - dest) - 1 : (int)(iend - anchor); if (lastRun >= RUN_MASK) { int 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); } Unsafe.CopyBlock(op, anchor, (uint)lastRun); op += lastRun; ip += lastRun; } _skip_last_literals: { var result = (int)(op - dest); source = ip; dest = op; return(result); } }