#region LZ4 original /* LZ4 - Fast LZ compression algorithm Copyright (C) 2011-2012, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html - LZ4 source repository : http://code.google.com/p/lz4/ */ #endregion #region LZ4 port /* Copyright (c) 2013, Milosz Krajewski All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #endregion // ReSharper disable CheckNamespace // ReSharper disable InconsistentNaming // ReSharper disable TooWideLocalVariableScope // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable RedundantIfElseBlock namespace MessagePack.LZ4 { public static partial class LZ4Codec { #region LZ4_compressCtx private static int LZ4_compressCtx_safe64( int[] hash_table, byte[] src, byte[] dst, int src_0, int dst_0, int src_len, int dst_maxlen) { unchecked { var debruijn64 = DEBRUIJN_TABLE_64; int _i; // ---- preprocessed source start here ---- // r93 var src_p = src_0; var src_base = src_0; var src_anchor = src_p; var src_end = src_p + src_len; var src_mflimit = src_end - MFLIMIT; var dst_p = dst_0; var dst_end = dst_p + dst_maxlen; var src_LASTLITERALS = src_end - LASTLITERALS; var src_LASTLITERALS_1 = src_LASTLITERALS - 1; var src_LASTLITERALS_3 = src_LASTLITERALS - 3; var src_LASTLITERALS_STEPSIZE_1 = src_LASTLITERALS - (STEPSIZE_64 - 1); var dst_LASTLITERALS_1 = dst_end - (1 + LASTLITERALS); var dst_LASTLITERALS_3 = dst_end - (2 + 1 + LASTLITERALS); int length; uint h, h_fwd; // Init if (src_len < MINLENGTH) goto _last_literals; // First Byte hash_table[(((Peek4(src, src_p)) * 2654435761u) >> HASH_ADJUST)] = (src_p - src_base); src_p++; h_fwd = (((Peek4(src, src_p)) * 2654435761u) >> HASH_ADJUST); // Main Loop while (true) { var findMatchAttempts = (1 << SKIPSTRENGTH) + 3; var src_p_fwd = src_p; int src_ref; int dst_token; // Find a match do { h = h_fwd; var step = findMatchAttempts++ >> SKIPSTRENGTH; src_p = src_p_fwd; src_p_fwd = src_p + step; if (src_p_fwd > src_mflimit) goto _last_literals; h_fwd = (((Peek4(src, src_p_fwd)) * 2654435761u) >> HASH_ADJUST); src_ref = src_base + hash_table[h]; hash_table[h] = (src_p - src_base); } while ((src_ref < src_p - MAX_DISTANCE) || (!Equal4(src, src_ref, src_p))); // Catch up while ((src_p > src_anchor) && (src_ref > src_0) && (src[src_p - 1] == src[src_ref - 1])) { src_p--; src_ref--; } // Encode Literal length length = (src_p - src_anchor); dst_token = dst_p++; if (dst_p + length + (length >> 8) > dst_LASTLITERALS_3) return 0; // Check output limit if (length >= RUN_MASK) { var len = length - RUN_MASK; dst[dst_token] = (RUN_MASK << ML_BITS); if (len > 254) { do { dst[dst_p++] = 255; len -= 255; } while (len > 254); dst[dst_p++] = (byte)len; BlockCopy(src, src_anchor, dst, dst_p, length); dst_p += length; goto _next_match; } else dst[dst_p++] = (byte)len; } else { dst[dst_token] = (byte)(length << ML_BITS); } // Copy Literals if (length > 0) { _i = dst_p + length; WildCopy(src, src_anchor, dst, dst_p, _i); dst_p = _i; } _next_match: // Encode Offset Poke2(dst, dst_p, (ushort)(src_p - src_ref)); dst_p += 2; // Start Counting src_p += MINMATCH; src_ref += MINMATCH; // MinMatch already verified src_anchor = src_p; while (src_p < src_LASTLITERALS_STEPSIZE_1) { var diff = (long)Xor8(src, src_ref, src_p); if (diff == 0) { src_p += STEPSIZE_64; src_ref += STEPSIZE_64; continue; } src_p += debruijn64[((ulong)((diff) & -(diff)) * 0x0218A392CDABBD3FL) >> 58]; goto _endCount; } if ((src_p < src_LASTLITERALS_3) && (Equal4(src, src_ref, src_p))) { src_p += 4; src_ref += 4; } if ((src_p < src_LASTLITERALS_1) && (Equal2(src, src_ref, src_p))) { src_p += 2; src_ref += 2; } if ((src_p < src_LASTLITERALS) && (src[src_ref] == src[src_p])) src_p++; _endCount: // Encode MatchLength length = (src_p - src_anchor); if (dst_p + (length >> 8) > dst_LASTLITERALS_1) return 0; // Check output limit if (length >= ML_MASK) { dst[dst_token] += ML_MASK; length -= ML_MASK; for (; length > 509; length -= 510) { dst[dst_p++] = 255; dst[dst_p++] = 255; } if (length > 254) { length -= 255; dst[dst_p++] = 255; } dst[dst_p++] = (byte)length; } else { dst[dst_token] += (byte)length; } // Test end of chunk if (src_p > src_mflimit) { src_anchor = src_p; break; } // Fill table hash_table[(((Peek4(src, src_p - 2)) * 2654435761u) >> HASH_ADJUST)] = (src_p - 2 - src_base); // Test next position h = (((Peek4(src, src_p)) * 2654435761u) >> HASH_ADJUST); src_ref = src_base + hash_table[h]; hash_table[h] = (src_p - src_base); if ((src_ref > src_p - (MAX_DISTANCE + 1)) && (Equal4(src, src_ref, src_p))) { dst_token = dst_p++; dst[dst_token] = 0; goto _next_match; } // Prepare next loop src_anchor = src_p++; h_fwd = (((Peek4(src, src_p)) * 2654435761u) >> HASH_ADJUST); } _last_literals: // Encode Last Literals { var lastRun = (src_end - src_anchor); if (dst_p + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > dst_end) return 0; if (lastRun >= RUN_MASK) { dst[dst_p++] = (RUN_MASK << ML_BITS); lastRun -= RUN_MASK; for (; lastRun > 254; lastRun -= 255) dst[dst_p++] = 255; dst[dst_p++] = (byte)lastRun; } else dst[dst_p++] = (byte)(lastRun << ML_BITS); BlockCopy(src, src_anchor, dst, dst_p, src_end - src_anchor); dst_p += src_end - src_anchor; } // End return (dst_p - dst_0); } } #endregion #region LZ4_compress64kCtx private static int LZ4_compress64kCtx_safe64( ushort[] hash_table, byte[] src, byte[] dst, int src_0, int dst_0, int src_len, int dst_maxlen) { unchecked { var debruijn64 = DEBRUIJN_TABLE_64; int _i; // ---- preprocessed source start here ---- // r93 var src_p = src_0; var src_anchor = src_p; var src_base = src_p; var src_end = src_p + src_len; var src_mflimit = src_end - MFLIMIT; var dst_p = dst_0; var dst_end = dst_p + dst_maxlen; var src_LASTLITERALS = src_end - LASTLITERALS; var src_LASTLITERALS_1 = src_LASTLITERALS - 1; var src_LASTLITERALS_3 = src_LASTLITERALS - 3; var src_LASTLITERALS_STEPSIZE_1 = src_LASTLITERALS - (STEPSIZE_64 - 1); var dst_LASTLITERALS_1 = dst_end - (1 + LASTLITERALS); var dst_LASTLITERALS_3 = dst_end - (2 + 1 + LASTLITERALS); int len, length; uint h, h_fwd; // Init if (src_len < MINLENGTH) goto _last_literals; // First Byte src_p++; h_fwd = (((Peek4(src, src_p)) * 2654435761u) >> HASH64K_ADJUST); // Main Loop while (true) { var findMatchAttempts = (1 << SKIPSTRENGTH) + 3; var src_p_fwd = src_p; int src_ref; int dst_token; // Find a match do { h = h_fwd; var step = findMatchAttempts++ >> SKIPSTRENGTH; src_p = src_p_fwd; src_p_fwd = src_p + step; if (src_p_fwd > src_mflimit) goto _last_literals; h_fwd = (((Peek4(src, src_p_fwd)) * 2654435761u) >> HASH64K_ADJUST); src_ref = src_base + hash_table[h]; hash_table[h] = (ushort)(src_p - src_base); } while (!Equal4(src, src_ref, src_p)); // Catch up while ((src_p > src_anchor) && (src_ref > src_0) && (src[src_p - 1] == src[src_ref - 1])) { src_p--; src_ref--; } // Encode Literal length length = (src_p - src_anchor); dst_token = dst_p++; if (dst_p + length + (length >> 8) > dst_LASTLITERALS_3) return 0; // Check output limit if (length >= RUN_MASK) { len = length - RUN_MASK; dst[dst_token] = (RUN_MASK << ML_BITS); if (len > 254) { do { dst[dst_p++] = 255; len -= 255; } while (len > 254); dst[dst_p++] = (byte)len; BlockCopy(src, src_anchor, dst, dst_p, length); dst_p += length; goto _next_match; } else dst[dst_p++] = (byte)len; } else { dst[dst_token] = (byte)(length << ML_BITS); } // Copy Literals if (length > 0) /*?*/ { _i = dst_p + length; WildCopy(src, src_anchor, dst, dst_p, _i); dst_p = _i; } _next_match: // Encode Offset Poke2(dst, dst_p, (ushort)(src_p - src_ref)); dst_p += 2; // Start Counting src_p += MINMATCH; src_ref += MINMATCH; // MinMatch verified src_anchor = src_p; while (src_p < src_LASTLITERALS_STEPSIZE_1) { var diff = (long)Xor8(src, src_ref, src_p); if (diff == 0) { src_p += STEPSIZE_64; src_ref += STEPSIZE_64; continue; } src_p += debruijn64[((ulong)((diff) & -(diff)) * 0x0218A392CDABBD3FL) >> 58]; goto _endCount; } if ((src_p < src_LASTLITERALS_3) && (Equal4(src, src_ref, src_p))) { src_p += 4; src_ref += 4; } if ((src_p < src_LASTLITERALS_1) && (Equal2(src, src_ref, src_p))) { src_p += 2; src_ref += 2; } if ((src_p < src_LASTLITERALS) && (src[src_ref] == src[src_p])) src_p++; _endCount: // Encode MatchLength len = (src_p - src_anchor); if (dst_p + (len >> 8) > dst_LASTLITERALS_1) return 0; // Check output limit if (len >= ML_MASK) { dst[dst_token] += ML_MASK; len -= ML_MASK; for (; len > 509; len -= 510) { dst[dst_p++] = 255; dst[dst_p++] = 255; } if (len > 254) { len -= 255; dst[dst_p++] = 255; } dst[dst_p++] = (byte)len; } else { dst[dst_token] += (byte)len; } // Test end of chunk if (src_p > src_mflimit) { src_anchor = src_p; break; } // Fill table hash_table[(((Peek4(src, src_p - 2)) * 2654435761u) >> HASH64K_ADJUST)] = (ushort)(src_p - 2 - src_base); // Test next position h = (((Peek4(src, src_p)) * 2654435761u) >> HASH64K_ADJUST); src_ref = src_base + hash_table[h]; hash_table[h] = (ushort)(src_p - src_base); if (Equal4(src, src_ref, src_p)) { dst_token = dst_p++; dst[dst_token] = 0; goto _next_match; } // Prepare next loop src_anchor = src_p++; h_fwd = (((Peek4(src, src_p)) * 2654435761u) >> HASH64K_ADJUST); } _last_literals: // Encode Last Literals { var lastRun = (src_end - src_anchor); if (dst_p + lastRun + 1 + (lastRun - RUN_MASK + 255) / 255 > dst_end) return 0; if (lastRun >= RUN_MASK) { dst[dst_p++] = (RUN_MASK << ML_BITS); lastRun -= RUN_MASK; for (; lastRun > 254; lastRun -= 255) dst[dst_p++] = 255; dst[dst_p++] = (byte)lastRun; } else dst[dst_p++] = (byte)(lastRun << ML_BITS); BlockCopy(src, src_anchor, dst, dst_p, src_end - src_anchor); dst_p += src_end - src_anchor; } // End return (dst_p - dst_0); } } #endregion #region LZ4_uncompress private static int LZ4_uncompress_safe64( byte[] src, byte[] dst, int src_0, int dst_0, int dst_len) { unchecked { var dec32table = DECODER_TABLE_32; var dec64table = DECODER_TABLE_64; int _i; // ---- preprocessed source start here ---- // r93 var src_p = src_0; int dst_ref; var dst_p = dst_0; var dst_end = dst_p + dst_len; int dst_cpy; var dst_LASTLITERALS = dst_end - LASTLITERALS; var dst_COPYLENGTH = dst_end - COPYLENGTH; var dst_COPYLENGTH_STEPSIZE_4 = dst_end - COPYLENGTH - (STEPSIZE_64 - 4); uint token; // Main Loop while (true) { int length; // get runlength token = src[src_p++]; if ((length = (byte)(token >> ML_BITS)) == RUN_MASK) { int len; for (; (len = src[src_p++]) == 255; length += 255) { /* do nothing */ } length += len; } // copy literals dst_cpy = dst_p + length; if (dst_cpy > dst_COPYLENGTH) { if (dst_cpy != dst_end) goto _output_error; // Error : not enough place for another match (min 4) + 5 literals BlockCopy(src, src_p, dst, dst_p, length); src_p += length; break; // EOF } if (dst_p < dst_cpy) /*?*/ { _i = WildCopy(src, src_p, dst, dst_p, dst_cpy); src_p += _i; dst_p += _i; } src_p -= (dst_p - dst_cpy); dst_p = dst_cpy; // get offset dst_ref = (dst_cpy) - Peek2(src, src_p); src_p += 2; if (dst_ref < dst_0) goto _output_error; // Error : offset outside destination buffer // get matchlength if ((length = (byte)(token & ML_MASK)) == ML_MASK) { for (; src[src_p] == 255; length += 255) src_p++; length += src[src_p++]; } // copy repeated sequence if ((dst_p - dst_ref) < STEPSIZE_64) { var dec64 = dec64table[dst_p - dst_ref]; dst[dst_p + 0] = dst[dst_ref + 0]; dst[dst_p + 1] = dst[dst_ref + 1]; dst[dst_p + 2] = dst[dst_ref + 2]; dst[dst_p + 3] = dst[dst_ref + 3]; dst_p += 4; dst_ref += 4; dst_ref -= dec32table[dst_p - dst_ref]; Copy4(dst, dst_ref, dst_p); dst_p += STEPSIZE_64 - 4; dst_ref -= dec64; } else { Copy8(dst, dst_ref, dst_p); dst_p += 8; dst_ref += 8; } dst_cpy = dst_p + length - (STEPSIZE_64 - 4); if (dst_cpy > dst_COPYLENGTH_STEPSIZE_4) { if (dst_cpy > dst_LASTLITERALS) goto _output_error; // Error : last 5 bytes must be literals if (dst_p < dst_COPYLENGTH) { _i = SecureCopy(dst, dst_ref, dst_p, dst_COPYLENGTH); dst_ref += _i; dst_p += _i; } while (dst_p < dst_cpy) dst[dst_p++] = dst[dst_ref++]; dst_p = dst_cpy; continue; } if (dst_p < dst_cpy) { SecureCopy(dst, dst_ref, dst_p, dst_cpy); } dst_p = dst_cpy; // correction } // end of decoding return ((src_p) - src_0); _output_error: // write overflow error detected return (-((src_p) - src_0)); } } #endregion } } // ReSharper restore RedundantIfElseBlock // ReSharper restore JoinDeclarationAndInitializer // ReSharper restore TooWideLocalVariableScope // ReSharper restore InconsistentNaming // ReSharper restore CheckNamespace