(ded4a3e0a) v0.9.0.7
This commit is contained in:
+608
@@ -0,0 +1,608 @@
|
||||
#region license
|
||||
|
||||
/*
|
||||
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
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content.Pipeline.Utilities.LZ4
|
||||
{
|
||||
/// <summary>Unsafe LZ4 codec.</summary>
|
||||
internal static partial class LZ4Codec
|
||||
{
|
||||
/// <summary>Copies block of memory.</summary>
|
||||
/// <param name="src">The source.</param>
|
||||
/// <param name="dst">The destination.</param>
|
||||
/// <param name="len">The length (in bytes).</param>
|
||||
private static unsafe void BlockCopy(byte* src, byte* dst, int len)
|
||||
{
|
||||
while (len >= 8)
|
||||
{
|
||||
*(ulong*)dst = *(ulong*)src;
|
||||
dst += 8;
|
||||
src += 8;
|
||||
len -= 8;
|
||||
}
|
||||
if (len >= 4)
|
||||
{
|
||||
*(uint*)dst = *(uint*)src;
|
||||
dst += 4;
|
||||
src += 4;
|
||||
len -= 4;
|
||||
}
|
||||
if (len >= 2)
|
||||
{
|
||||
*(ushort*)dst = *(ushort*)src;
|
||||
dst += 2;
|
||||
src += 2;
|
||||
len -= 2;
|
||||
}
|
||||
if (len >= 1)
|
||||
{
|
||||
*dst = *src; /* d++; s++; l--; */
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Copies block of memory.</summary>
|
||||
/// <param name="dst">The destination.</param>
|
||||
/// <param name="len">The length (in bytes).</param>
|
||||
/// <param name="val">The value.</param>
|
||||
private static unsafe void BlockFill(byte* dst, int len, byte val)
|
||||
{
|
||||
if (len >= 8)
|
||||
{
|
||||
ulong mask = val;
|
||||
mask |= mask << 8;
|
||||
mask |= mask << 16;
|
||||
mask |= mask << 32;
|
||||
do
|
||||
{
|
||||
*(ulong*)dst = mask;
|
||||
dst += 8;
|
||||
len -= 8;
|
||||
} while (len >= 8);
|
||||
}
|
||||
|
||||
while (len-- > 0) *dst++ = val;
|
||||
}
|
||||
|
||||
#region Encode32
|
||||
|
||||
/// <summary>Encodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <returns>Number of bytes written.</returns>
|
||||
public static unsafe int Encode32(
|
||||
byte* input,
|
||||
byte* output,
|
||||
int inputLength,
|
||||
int outputLength)
|
||||
{
|
||||
if (inputLength < LZ4_64KLIMIT)
|
||||
{
|
||||
var hashTable = new ushort[HASH64K_TABLESIZE];
|
||||
fixed (ushort* h = &hashTable[0])
|
||||
{
|
||||
return LZ4_compress64kCtx_32(h, input, output, inputLength, outputLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var hashTable = new byte*[HASH_TABLESIZE];
|
||||
fixed (byte** h = &hashTable[0])
|
||||
{
|
||||
return LZ4_compressCtx_32(h, input, output, inputLength, outputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Encodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="outputOffset">The output offset.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <returns>Number of bytes written.</returns>
|
||||
public static unsafe int Encode32(
|
||||
byte[] input,
|
||||
int inputOffset,
|
||||
int inputLength,
|
||||
byte[] output,
|
||||
int outputOffset,
|
||||
int outputLength)
|
||||
{
|
||||
CheckArguments(
|
||||
input, inputOffset, ref inputLength,
|
||||
output, outputOffset, ref outputLength);
|
||||
|
||||
if (outputLength == 0) return 0;
|
||||
|
||||
fixed (byte* inputPtr = &input[inputOffset])
|
||||
fixed (byte* outputPtr = &output[outputOffset])
|
||||
{
|
||||
return Encode32(inputPtr, outputPtr, inputLength, outputLength);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Encodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <returns>Compressed buffer.</returns>
|
||||
public static byte[] Encode32(byte[] input, int inputOffset, int inputLength)
|
||||
{
|
||||
if (inputLength < 0) inputLength = input.Length - inputOffset;
|
||||
|
||||
if (input == null) throw new ArgumentNullException("input");
|
||||
if (inputOffset < 0 || inputOffset + inputLength > input.Length)
|
||||
throw new ArgumentException("inputOffset and inputLength are invalid for given input");
|
||||
|
||||
var result = new byte[MaximumOutputLength(inputLength)];
|
||||
var length = Encode32(input, inputOffset, inputLength, result, 0, result.Length);
|
||||
|
||||
if (length != result.Length)
|
||||
{
|
||||
if (length < 0)
|
||||
throw new InvalidOperationException("Compression has been corrupted");
|
||||
var buffer = new byte[length];
|
||||
Buffer.BlockCopy(result, 0, buffer, 0, length);
|
||||
return buffer;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Decode32
|
||||
|
||||
/// <summary>Decodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <param name="knownOutputLength">Set it to <c>true</c> if output length is known.</param>
|
||||
/// <returns>Number of bytes written.</returns>
|
||||
public static unsafe int Decode32(
|
||||
byte* input,
|
||||
int inputLength,
|
||||
byte* output,
|
||||
int outputLength,
|
||||
bool knownOutputLength)
|
||||
{
|
||||
if (knownOutputLength)
|
||||
{
|
||||
var length = LZ4_uncompress_32(input, output, outputLength);
|
||||
if (length != inputLength)
|
||||
throw new ArgumentException("LZ4 block is corrupted, or invalid length has been given.");
|
||||
return outputLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
var length = LZ4_uncompress_unknownOutputSize_32(input, output, inputLength, outputLength);
|
||||
if (length < 0)
|
||||
throw new ArgumentException("LZ4 block is corrupted, or invalid length has been given.");
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Decodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="outputOffset">The output offset.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <param name="knownOutputLength">Set it to <c>true</c> if output length is known.</param>
|
||||
/// <returns>Number of bytes written.</returns>
|
||||
public static unsafe int Decode32(
|
||||
byte[] input,
|
||||
int inputOffset,
|
||||
int inputLength,
|
||||
byte[] output,
|
||||
int outputOffset,
|
||||
int outputLength,
|
||||
bool knownOutputLength)
|
||||
{
|
||||
CheckArguments(
|
||||
input, inputOffset, ref inputLength,
|
||||
output, outputOffset, ref outputLength);
|
||||
|
||||
if (outputLength == 0) return 0;
|
||||
|
||||
fixed (byte* inputPtr = &input[inputOffset])
|
||||
fixed (byte* outputPtr = &output[outputOffset])
|
||||
{
|
||||
return Decode32(inputPtr, inputLength, outputPtr, outputLength, knownOutputLength);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Decodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <returns>Decompressed buffer.</returns>
|
||||
public static byte[] Decode32(byte[] input, int inputOffset, int inputLength, int outputLength)
|
||||
{
|
||||
if (inputLength < 0) inputLength = input.Length - inputOffset;
|
||||
|
||||
if (input == null) throw new ArgumentNullException("input");
|
||||
if (inputOffset < 0 || inputOffset + inputLength > input.Length)
|
||||
throw new ArgumentException("inputOffset and inputLength are invalid for given input");
|
||||
|
||||
var result = new byte[outputLength];
|
||||
var length = Decode32(input, inputOffset, inputLength, result, 0, outputLength, true);
|
||||
if (length != outputLength)
|
||||
throw new ArgumentException("outputLength is not valid");
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Encode64
|
||||
|
||||
/// <summary>Encodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <returns>Number of bytes written.</returns>
|
||||
public static unsafe int Encode64(
|
||||
byte* input,
|
||||
byte* output,
|
||||
int inputLength,
|
||||
int outputLength)
|
||||
{
|
||||
if (inputLength < LZ4_64KLIMIT)
|
||||
{
|
||||
var hashTable = new ushort[HASH64K_TABLESIZE];
|
||||
fixed (ushort* h = &hashTable[0])
|
||||
{
|
||||
return LZ4_compress64kCtx_64(h, input, output, inputLength, outputLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var hashTable = new uint[HASH_TABLESIZE];
|
||||
fixed (uint* h = &hashTable[0])
|
||||
{
|
||||
return LZ4_compressCtx_64(h, input, output, inputLength, outputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Encodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="outputOffset">The output offset.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <returns>Number of bytes written.</returns>
|
||||
public static unsafe int Encode64(
|
||||
byte[] input,
|
||||
int inputOffset,
|
||||
int inputLength,
|
||||
byte[] output,
|
||||
int outputOffset,
|
||||
int outputLength)
|
||||
{
|
||||
CheckArguments(
|
||||
input, inputOffset, ref inputLength,
|
||||
output, outputOffset, ref outputLength);
|
||||
|
||||
if (outputLength == 0) return 0;
|
||||
|
||||
fixed (byte* inputPtr = &input[inputOffset])
|
||||
fixed (byte* outputPtr = &output[outputOffset])
|
||||
{
|
||||
return Encode64(inputPtr, outputPtr, inputLength, outputLength);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Encodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <returns>Compressed buffer.</returns>
|
||||
public static byte[] Encode64(byte[] input, int inputOffset, int inputLength)
|
||||
{
|
||||
if (inputLength < 0) inputLength = input.Length - inputOffset;
|
||||
|
||||
if (input == null) throw new ArgumentNullException("input");
|
||||
if (inputOffset < 0 || inputOffset + inputLength > input.Length)
|
||||
throw new ArgumentException("inputOffset and inputLength are invalid for given input");
|
||||
|
||||
var result = new byte[MaximumOutputLength(inputLength)];
|
||||
var length = Encode64(input, inputOffset, inputLength, result, 0, result.Length);
|
||||
|
||||
if (length != result.Length)
|
||||
{
|
||||
if (length < 0)
|
||||
throw new InvalidOperationException("Compression has been corrupted");
|
||||
var buffer = new byte[length];
|
||||
Buffer.BlockCopy(result, 0, buffer, 0, length);
|
||||
return buffer;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Decode64
|
||||
|
||||
/// <summary>Decodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <param name="knownOutputLength">Set it to <c>true</c> if output length is known.</param>
|
||||
/// <returns>Number of bytes written.</returns>
|
||||
public static unsafe int Decode64(
|
||||
byte* input,
|
||||
int inputLength,
|
||||
byte* output,
|
||||
int outputLength,
|
||||
bool knownOutputLength)
|
||||
{
|
||||
if (knownOutputLength)
|
||||
{
|
||||
var length = LZ4_uncompress_64(input, output, outputLength);
|
||||
if (length != inputLength)
|
||||
throw new ArgumentException("LZ4 block is corrupted, or invalid length has been given.");
|
||||
return outputLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
var length = LZ4_uncompress_unknownOutputSize_64(input, output, inputLength, outputLength);
|
||||
if (length < 0)
|
||||
throw new ArgumentException("LZ4 block is corrupted, or invalid length has been given.");
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Decode64s the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="outputOffset">The output offset.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <param name="knownOutputLength">Set it to <c>true</c> if output length is known.</param>
|
||||
/// <returns>Number of bytes written.</returns>
|
||||
public static unsafe int Decode64(
|
||||
byte[] input,
|
||||
int inputOffset,
|
||||
int inputLength,
|
||||
byte[] output,
|
||||
int outputOffset,
|
||||
int outputLength,
|
||||
bool knownOutputLength)
|
||||
{
|
||||
CheckArguments(
|
||||
input, inputOffset, ref inputLength,
|
||||
output, outputOffset, ref outputLength);
|
||||
|
||||
if (outputLength == 0) return 0;
|
||||
|
||||
fixed (byte* inputPtr = &input[inputOffset])
|
||||
fixed (byte* outputPtr = &output[outputOffset])
|
||||
{
|
||||
return Decode64(inputPtr, inputLength, outputPtr, outputLength, knownOutputLength);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Decode64s the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <returns>Decompressed buffer.</returns>
|
||||
public static byte[] Decode64(byte[] input, int inputOffset, int inputLength, int outputLength)
|
||||
{
|
||||
if (inputLength < 0) inputLength = input.Length - inputOffset;
|
||||
|
||||
if (input == null) throw new ArgumentNullException("input");
|
||||
if (inputOffset < 0 || inputOffset + inputLength > input.Length)
|
||||
throw new ArgumentException("inputOffset and inputLength are invalid for given input");
|
||||
|
||||
var result = new byte[outputLength];
|
||||
var length = Decode64(input, inputOffset, inputLength, result, 0, outputLength, true);
|
||||
if (length != outputLength)
|
||||
throw new ArgumentException("outputLength is not valid");
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region HC utilities
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
private unsafe class LZ4HC_Data_Structure
|
||||
{
|
||||
public byte* src_base;
|
||||
public byte* nextToUpdate;
|
||||
public int[] hashTable;
|
||||
public ushort[] chainTable;
|
||||
};
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
|
||||
private static unsafe LZ4HC_Data_Structure LZ4HC_Create(byte* src)
|
||||
{
|
||||
var hc4 = new LZ4HC_Data_Structure {
|
||||
hashTable = new int[HASHHC_TABLESIZE],
|
||||
chainTable = new ushort[MAXD]
|
||||
};
|
||||
|
||||
fixed (ushort* ct = &hc4.chainTable[0])
|
||||
{
|
||||
BlockFill((byte*)ct, MAXD * sizeof(ushort), 0xFF);
|
||||
}
|
||||
|
||||
hc4.src_base = src;
|
||||
hc4.nextToUpdate = src + 1;
|
||||
|
||||
return hc4;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Encode32HC
|
||||
|
||||
private static unsafe int LZ4_compressHC_32(byte* input, byte* output, int inputLength, int outputLength)
|
||||
{
|
||||
return LZ4_compressHCCtx_32(LZ4HC_Create(input), input, output, inputLength, outputLength);
|
||||
}
|
||||
|
||||
/// <summary>Encodes the specified input using HC codec.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="outputOffset">The output offset.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <returns>Number of bytes written. NOTE: when output buffer is too small it returns negative value.</returns>
|
||||
public static unsafe int Encode32HC(
|
||||
byte[] input,
|
||||
int inputOffset,
|
||||
int inputLength,
|
||||
byte[] output,
|
||||
int outputOffset,
|
||||
int outputLength)
|
||||
{
|
||||
if (inputLength == 0) return 0;
|
||||
|
||||
CheckArguments(
|
||||
input, inputOffset, ref inputLength,
|
||||
output, outputOffset, ref outputLength);
|
||||
|
||||
fixed (byte* inputPtr = &input[inputOffset])
|
||||
fixed (byte* outputPtr = &output[outputOffset])
|
||||
{
|
||||
var length = LZ4_compressHC_32(inputPtr, outputPtr, inputLength, outputLength);
|
||||
return length <= 0 ? -1 : length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Encodes the specified input using HC codec.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <returns>Buffer with compressed data (NOTE: it can be bigger than input).</returns>
|
||||
public static byte[] Encode32HC(
|
||||
byte[] input, int inputOffset, int inputLength)
|
||||
{
|
||||
if (inputLength == 0) return new byte[0];
|
||||
var outputLength = MaximumOutputLength(inputLength);
|
||||
var result = new byte[outputLength];
|
||||
var length = Encode32HC(input, inputOffset, inputLength, result, 0, outputLength);
|
||||
|
||||
if (length < 0)
|
||||
throw new ArgumentException("Provided data seems to be corrupted.");
|
||||
|
||||
if (length != outputLength)
|
||||
{
|
||||
var buffer = new byte[length];
|
||||
Buffer.BlockCopy(result, 0, buffer, 0, length);
|
||||
result = buffer;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Encode64HC
|
||||
|
||||
private static unsafe int LZ4_compressHC_64(byte* input, byte* output, int inputLength, int outputLength)
|
||||
{
|
||||
return LZ4_compressHCCtx_64(LZ4HC_Create(input), input, output, inputLength, outputLength);
|
||||
}
|
||||
|
||||
/// <summary>Encodes the specified input using HC codec.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="outputOffset">The output offset.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <returns>Number of bytes written. NOTE: when output buffer is too small it returns negative value.</returns>
|
||||
public static unsafe int Encode64HC(
|
||||
byte[] input,
|
||||
int inputOffset,
|
||||
int inputLength,
|
||||
byte[] output,
|
||||
int outputOffset,
|
||||
int outputLength)
|
||||
{
|
||||
if (inputLength == 0) return 0;
|
||||
|
||||
CheckArguments(
|
||||
input, inputOffset, ref inputLength,
|
||||
output, outputOffset, ref outputLength);
|
||||
|
||||
fixed (byte* inputPtr = &input[inputOffset])
|
||||
fixed (byte* outputPtr = &output[outputOffset])
|
||||
{
|
||||
var length = LZ4_compressHC_64(inputPtr, outputPtr, inputLength, outputLength);
|
||||
return length <= 0 ? -1 : length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Encodes the specified input using HC codec.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <returns>Buffer with compressed data (NOTE: it can be bigger than input).</returns>
|
||||
public static byte[] Encode64HC(
|
||||
byte[] input, int inputOffset, int inputLength)
|
||||
{
|
||||
if (inputLength == 0) return new byte[0];
|
||||
var outputLength = MaximumOutputLength(inputLength);
|
||||
var result = new byte[outputLength];
|
||||
var length = Encode64HC(input, inputOffset, inputLength, result, 0, outputLength);
|
||||
|
||||
if (length < 0)
|
||||
throw new ArgumentException("Provided data seems to be corrupted.");
|
||||
|
||||
if (length != outputLength)
|
||||
{
|
||||
var buffer = new byte[length];
|
||||
Buffer.BlockCopy(result, 0, buffer, 0, length);
|
||||
result = buffer;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
+822
@@ -0,0 +1,822 @@
|
||||
#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 InconsistentNaming
|
||||
// ReSharper disable TooWideLocalVariableScope
|
||||
// ReSharper disable JoinDeclarationAndInitializer
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content.Pipeline.Utilities.LZ4
|
||||
{
|
||||
internal static partial class LZ4Codec
|
||||
{
|
||||
#region LZ4_compressCtx_32
|
||||
|
||||
private static unsafe int LZ4_compressCtx_32(
|
||||
byte** hash_table,
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
byte* _p;
|
||||
|
||||
fixed (int* debruijn32 = &DEBRUIJN_TABLE_32[0])
|
||||
{
|
||||
// r93
|
||||
var src_p = src;
|
||||
const int src_base = 0;
|
||||
var src_anchor = src_p;
|
||||
var src_end = src_p + src_len;
|
||||
var src_mflimit = src_end - MFLIMIT;
|
||||
|
||||
var dst_p = dst;
|
||||
var dst_end = dst_p + dst_maxlen;
|
||||
|
||||
var src_LASTLITERALS = src_end - LASTLITERALS;
|
||||
var src_LASTLITERALS_1 = src_LASTLITERALS - 1;
|
||||
|
||||
var src_LASTLITERALS_STEPSIZE_1 = src_LASTLITERALS - (STEPSIZE_32 - 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[((((*(uint*)(src_p))) * 2654435761u) >> HASH_ADJUST)] = (src_p - src_base);
|
||||
src_p++;
|
||||
h_fwd = ((((*(uint*)(src_p))) * 2654435761u) >> HASH_ADJUST);
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
var findMatchAttempts = (1 << SKIPSTRENGTH) + 3;
|
||||
var src_p_fwd = src_p;
|
||||
byte* xxx_ref;
|
||||
byte* xxx_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 = ((((*(uint*)(src_p_fwd))) * 2654435761u) >> HASH_ADJUST);
|
||||
xxx_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (src_p - src_base);
|
||||
} while ((xxx_ref < src_p - MAX_DISTANCE) || ((*(uint*)(xxx_ref)) != (*(uint*)(src_p))));
|
||||
|
||||
// Catch up
|
||||
while ((src_p > src_anchor) && (xxx_ref > src) && (src_p[-1] == xxx_ref[-1]))
|
||||
{
|
||||
src_p--;
|
||||
xxx_ref--;
|
||||
}
|
||||
|
||||
// Encode Literal length
|
||||
length = (int)(src_p - src_anchor);
|
||||
xxx_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;
|
||||
*xxx_token = (RUN_MASK << ML_BITS);
|
||||
if (len > 254)
|
||||
{
|
||||
do
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
len -= 255;
|
||||
} while (len > 254);
|
||||
*dst_p++ = (byte)len;
|
||||
BlockCopy(src_anchor, dst_p, (length));
|
||||
dst_p += length;
|
||||
goto _next_match;
|
||||
}
|
||||
*dst_p++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*xxx_token = (byte)(length << ML_BITS);
|
||||
}
|
||||
|
||||
// Copy Literals
|
||||
_p = dst_p + (length);
|
||||
do
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)src_anchor;
|
||||
dst_p += 4;
|
||||
src_anchor += 4;
|
||||
*(uint*)dst_p = *(uint*)src_anchor;
|
||||
dst_p += 4;
|
||||
src_anchor += 4;
|
||||
} while (dst_p < _p);
|
||||
dst_p = _p;
|
||||
|
||||
_next_match:
|
||||
|
||||
// Encode Offset
|
||||
*(ushort*)dst_p = (ushort)(src_p - xxx_ref);
|
||||
dst_p += 2;
|
||||
|
||||
// Start Counting
|
||||
src_p += MINMATCH;
|
||||
xxx_ref += MINMATCH; // MinMatch already verified
|
||||
src_anchor = src_p;
|
||||
|
||||
while (src_p < src_LASTLITERALS_STEPSIZE_1)
|
||||
{
|
||||
var diff = (*(int*)(xxx_ref)) ^ (*(int*)(src_p));
|
||||
if (diff == 0)
|
||||
{
|
||||
src_p += STEPSIZE_32;
|
||||
xxx_ref += STEPSIZE_32;
|
||||
continue;
|
||||
}
|
||||
src_p += debruijn32[(((uint)((diff) & -(diff)) * 0x077CB531u)) >> 27];
|
||||
goto _endCount;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS_1) && ((*(ushort*)(xxx_ref)) == (*(ushort*)(src_p))))
|
||||
{
|
||||
src_p += 2;
|
||||
xxx_ref += 2;
|
||||
}
|
||||
if ((src_p < src_LASTLITERALS) && (*xxx_ref == *src_p)) src_p++;
|
||||
|
||||
_endCount:
|
||||
|
||||
// Encode MatchLength
|
||||
length = (int)(src_p - src_anchor);
|
||||
|
||||
if (dst_p + (length >> 8) > dst_LASTLITERALS_1) return 0; // Check output limit
|
||||
|
||||
if (length >= ML_MASK)
|
||||
{
|
||||
*xxx_token += ML_MASK;
|
||||
length -= ML_MASK;
|
||||
for (; length > 509; length -= 510)
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
if (length > 254)
|
||||
{
|
||||
length -= 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
*dst_p++ = (byte)length;
|
||||
}
|
||||
else
|
||||
{
|
||||
*xxx_token += (byte)length;
|
||||
}
|
||||
|
||||
// Test end of chunk
|
||||
if (src_p > src_mflimit)
|
||||
{
|
||||
src_anchor = src_p;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill table
|
||||
hash_table[((((*(uint*)(src_p - 2))) * 2654435761u) >> HASH_ADJUST)] = (src_p - 2 - src_base);
|
||||
|
||||
// Test next position
|
||||
|
||||
h = ((((*(uint*)(src_p))) * 2654435761u) >> HASH_ADJUST);
|
||||
xxx_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (src_p - src_base);
|
||||
|
||||
if ((xxx_ref > src_p - (MAX_DISTANCE + 1)) && ((*(uint*)(xxx_ref)) == (*(uint*)(src_p))))
|
||||
{
|
||||
xxx_token = dst_p++;
|
||||
*xxx_token = 0;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
// Prepare next loop
|
||||
src_anchor = src_p++;
|
||||
h_fwd = ((((*(uint*)(src_p))) * 2654435761u) >> HASH_ADJUST);
|
||||
}
|
||||
|
||||
_last_literals:
|
||||
|
||||
// Encode Last Literals
|
||||
{
|
||||
var lastRun = (int)(src_end - src_anchor);
|
||||
|
||||
if (dst_p + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > dst_end) return 0;
|
||||
|
||||
if (lastRun >= RUN_MASK)
|
||||
{
|
||||
*dst_p++ = (RUN_MASK << ML_BITS);
|
||||
lastRun -= RUN_MASK;
|
||||
for (; lastRun > 254; lastRun -= 255) *dst_p++ = 255;
|
||||
*dst_p++ = (byte)lastRun;
|
||||
}
|
||||
else *dst_p++ = (byte)(lastRun << ML_BITS);
|
||||
BlockCopy(src_anchor, dst_p, (int)(src_end - src_anchor));
|
||||
dst_p += src_end - src_anchor;
|
||||
}
|
||||
|
||||
// End
|
||||
return (int)((dst_p) - dst);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4_compress64kCtx_32
|
||||
|
||||
private static unsafe int LZ4_compress64kCtx_32(
|
||||
ushort* hash_table,
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
byte* _p;
|
||||
|
||||
fixed (int* debruijn32 = &DEBRUIJN_TABLE_32[0])
|
||||
{
|
||||
// r93
|
||||
var src_p = src;
|
||||
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;
|
||||
var dst_end = dst_p + dst_maxlen;
|
||||
|
||||
var src_LASTLITERALS = src_end - LASTLITERALS;
|
||||
var src_LASTLITERALS_1 = src_LASTLITERALS - 1;
|
||||
|
||||
var src_LASTLITERALS_STEPSIZE_1 = src_LASTLITERALS - (STEPSIZE_32 - 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 = ((((*(uint*)(src_p))) * 2654435761u) >> HASH64K_ADJUST);
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
var findMatchAttempts = (1 << SKIPSTRENGTH) + 3;
|
||||
var src_p_fwd = src_p;
|
||||
byte* xxx_ref;
|
||||
byte* xxx_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 = ((((*(uint*)(src_p_fwd))) * 2654435761u) >> HASH64K_ADJUST);
|
||||
xxx_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (ushort)(src_p - src_base);
|
||||
} while ((*(uint*)(xxx_ref)) != (*(uint*)(src_p)));
|
||||
|
||||
// Catch up
|
||||
while ((src_p > src_anchor) && (xxx_ref > src) && (src_p[-1] == xxx_ref[-1]))
|
||||
{
|
||||
src_p--;
|
||||
xxx_ref--;
|
||||
}
|
||||
|
||||
// Encode Literal length
|
||||
length = (int)(src_p - src_anchor);
|
||||
xxx_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;
|
||||
*xxx_token = (RUN_MASK << ML_BITS);
|
||||
if (len > 254)
|
||||
{
|
||||
do
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
len -= 255;
|
||||
} while (len > 254);
|
||||
*dst_p++ = (byte)len;
|
||||
BlockCopy(src_anchor, dst_p, (length));
|
||||
dst_p += length;
|
||||
goto _next_match;
|
||||
}
|
||||
*dst_p++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*xxx_token = (byte)(length << ML_BITS);
|
||||
}
|
||||
|
||||
// Copy Literals
|
||||
_p = dst_p + (length);
|
||||
do
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)src_anchor;
|
||||
dst_p += 4;
|
||||
src_anchor += 4;
|
||||
*(uint*)dst_p = *(uint*)src_anchor;
|
||||
dst_p += 4;
|
||||
src_anchor += 4;
|
||||
} while (dst_p < _p);
|
||||
dst_p = _p;
|
||||
|
||||
_next_match:
|
||||
|
||||
// Encode Offset
|
||||
*(ushort*)dst_p = (ushort)(src_p - xxx_ref);
|
||||
dst_p += 2;
|
||||
|
||||
// Start Counting
|
||||
src_p += MINMATCH;
|
||||
xxx_ref += MINMATCH; // MinMatch verified
|
||||
src_anchor = src_p;
|
||||
|
||||
while (src_p < src_LASTLITERALS_STEPSIZE_1)
|
||||
{
|
||||
var diff = (*(int*)(xxx_ref)) ^ (*(int*)(src_p));
|
||||
if (diff == 0)
|
||||
{
|
||||
src_p += STEPSIZE_32;
|
||||
xxx_ref += STEPSIZE_32;
|
||||
continue;
|
||||
}
|
||||
src_p += debruijn32[(((uint)((diff) & -(diff)) * 0x077CB531u)) >> 27];
|
||||
goto _endCount;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS_1) && ((*(ushort*)(xxx_ref)) == (*(ushort*)(src_p))))
|
||||
{
|
||||
src_p += 2;
|
||||
xxx_ref += 2;
|
||||
}
|
||||
if ((src_p < src_LASTLITERALS) && (*xxx_ref == *src_p)) src_p++;
|
||||
|
||||
_endCount:
|
||||
|
||||
// Encode MatchLength
|
||||
len = (int)(src_p - src_anchor);
|
||||
|
||||
if (dst_p + (len >> 8) > dst_LASTLITERALS_1) return 0; // Check output limit
|
||||
|
||||
if (len >= ML_MASK)
|
||||
{
|
||||
*xxx_token += ML_MASK;
|
||||
len -= ML_MASK;
|
||||
for (; len > 509; len -= 510)
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
if (len > 254)
|
||||
{
|
||||
len -= 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
*dst_p++ = (byte)len;
|
||||
}
|
||||
else *xxx_token += (byte)len;
|
||||
|
||||
// Test end of chunk
|
||||
if (src_p > src_mflimit)
|
||||
{
|
||||
src_anchor = src_p;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill table
|
||||
hash_table[((((*(uint*)(src_p - 2))) * 2654435761u) >> HASH64K_ADJUST)] = (ushort)(src_p - 2 - src_base);
|
||||
|
||||
// Test next position
|
||||
|
||||
h = ((((*(uint*)(src_p))) * 2654435761u) >> HASH64K_ADJUST);
|
||||
xxx_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (ushort)(src_p - src_base);
|
||||
|
||||
if ((*(uint*)(xxx_ref)) == (*(uint*)(src_p)))
|
||||
{
|
||||
xxx_token = dst_p++;
|
||||
*xxx_token = 0;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
// Prepare next loop
|
||||
src_anchor = src_p++;
|
||||
h_fwd = ((((*(uint*)(src_p))) * 2654435761u) >> HASH64K_ADJUST);
|
||||
}
|
||||
|
||||
_last_literals:
|
||||
|
||||
// Encode Last Literals
|
||||
{
|
||||
var lastRun = (int)(src_end - src_anchor);
|
||||
if (dst_p + lastRun + 1 + (lastRun - RUN_MASK + 255) / 255 > dst_end) return 0;
|
||||
if (lastRun >= RUN_MASK)
|
||||
{
|
||||
*dst_p++ = (RUN_MASK << ML_BITS);
|
||||
lastRun -= RUN_MASK;
|
||||
for (; lastRun > 254; lastRun -= 255) *dst_p++ = 255;
|
||||
*dst_p++ = (byte)lastRun;
|
||||
}
|
||||
else *dst_p++ = (byte)(lastRun << ML_BITS);
|
||||
BlockCopy(src_anchor, dst_p, (int)(src_end - src_anchor));
|
||||
dst_p += src_end - src_anchor;
|
||||
}
|
||||
|
||||
// End
|
||||
return (int)((dst_p) - dst);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4_uncompress_32
|
||||
|
||||
private static unsafe int LZ4_uncompress_32(
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int dst_len)
|
||||
{
|
||||
fixed (int* dec32table = &DECODER_TABLE_32[0])
|
||||
{
|
||||
// r93
|
||||
var src_p = src;
|
||||
byte* xxx_ref;
|
||||
|
||||
var dst_p = dst;
|
||||
var dst_end = dst_p + dst_len;
|
||||
byte* dst_cpy;
|
||||
|
||||
var dst_LASTLITERALS = dst_end - LASTLITERALS;
|
||||
var dst_COPYLENGTH = dst_end - COPYLENGTH;
|
||||
var dst_COPYLENGTH_STEPSIZE_4 = dst_end - COPYLENGTH - (STEPSIZE_32 - 4);
|
||||
|
||||
uint xxx_token;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
int length;
|
||||
|
||||
// get runlength
|
||||
xxx_token = *src_p++;
|
||||
if ((length = (int)(xxx_token >> ML_BITS)) == RUN_MASK)
|
||||
{
|
||||
int len;
|
||||
for (; (len = *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_p, dst_p, (length));
|
||||
src_p += length;
|
||||
break; // EOF
|
||||
}
|
||||
do
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)src_p;
|
||||
dst_p += 4;
|
||||
src_p += 4;
|
||||
*(uint*)dst_p = *(uint*)src_p;
|
||||
dst_p += 4;
|
||||
src_p += 4;
|
||||
} while (dst_p < dst_cpy);
|
||||
src_p -= (dst_p - dst_cpy);
|
||||
dst_p = dst_cpy;
|
||||
|
||||
// get offset
|
||||
xxx_ref = (dst_cpy) - (*(ushort*)(src_p));
|
||||
src_p += 2;
|
||||
if (xxx_ref < dst) goto _output_error; // Error : offset outside destination buffer
|
||||
|
||||
// get matchlength
|
||||
if ((length = (int)(xxx_token & ML_MASK)) == ML_MASK)
|
||||
{
|
||||
for (; *src_p == 255; length += 255) src_p++;
|
||||
length += *src_p++;
|
||||
}
|
||||
|
||||
// copy repeated sequence
|
||||
if ((dst_p - xxx_ref) < STEPSIZE_32)
|
||||
{
|
||||
const int dec64 = 0;
|
||||
|
||||
dst_p[0] = xxx_ref[0];
|
||||
dst_p[1] = xxx_ref[1];
|
||||
dst_p[2] = xxx_ref[2];
|
||||
dst_p[3] = xxx_ref[3];
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
xxx_ref -= dec32table[dst_p - xxx_ref];
|
||||
(*(uint*)(dst_p)) = (*(uint*)(xxx_ref));
|
||||
dst_p += STEPSIZE_32 - 4;
|
||||
xxx_ref -= dec64;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
}
|
||||
dst_cpy = dst_p + length - (STEPSIZE_32 - 4);
|
||||
|
||||
if (dst_cpy > dst_COPYLENGTH_STEPSIZE_4)
|
||||
{
|
||||
if (dst_cpy > dst_LASTLITERALS) goto _output_error; // Error : last 5 bytes must be literals
|
||||
{
|
||||
do
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
} while (dst_p < dst_COPYLENGTH);
|
||||
}
|
||||
|
||||
while (dst_p < dst_cpy) *dst_p++ = *xxx_ref++;
|
||||
dst_p = dst_cpy;
|
||||
continue;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
} while (dst_p < dst_cpy);
|
||||
dst_p = dst_cpy; // correction
|
||||
}
|
||||
|
||||
// end of decoding
|
||||
return (int)((src_p) - src);
|
||||
|
||||
// write overflow error detected
|
||||
_output_error:
|
||||
return (int)(-((src_p) - src));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4_uncompress_unknownOutputSize_32
|
||||
|
||||
private static unsafe int LZ4_uncompress_unknownOutputSize_32(
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
fixed (int* dec32table = &DECODER_TABLE_32[0])
|
||||
{
|
||||
// r93
|
||||
var src_p = src;
|
||||
var src_end = src_p + src_len;
|
||||
byte* xxx_ref;
|
||||
|
||||
var dst_p = dst;
|
||||
var dst_end = dst_p + dst_maxlen;
|
||||
byte* dst_cpy;
|
||||
|
||||
var src_LASTLITERALS_3 = (src_end - (2 + 1 + LASTLITERALS));
|
||||
var src_LASTLITERALS_1 = (src_end - (LASTLITERALS + 1));
|
||||
var dst_COPYLENGTH = (dst_end - COPYLENGTH);
|
||||
var dst_COPYLENGTH_STEPSIZE_4 = (dst_end - (COPYLENGTH + (STEPSIZE_32 - 4)));
|
||||
var dst_LASTLITERALS = (dst_end - LASTLITERALS);
|
||||
var dst_MFLIMIT = (dst_end - MFLIMIT);
|
||||
|
||||
// Special case
|
||||
if (src_p == src_end) goto _output_error; // A correctly formed null-compressed LZ4 must have at least one byte (token=0)
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
uint xxx_token;
|
||||
int length;
|
||||
|
||||
// get runlength
|
||||
xxx_token = *src_p++;
|
||||
if ((length = (int)(xxx_token >> ML_BITS)) == RUN_MASK)
|
||||
{
|
||||
var s = 255;
|
||||
while ((src_p < src_end) && (s == 255))
|
||||
{
|
||||
s = *src_p++;
|
||||
length += s;
|
||||
}
|
||||
}
|
||||
|
||||
// copy literals
|
||||
dst_cpy = dst_p + length;
|
||||
|
||||
if ((dst_cpy > dst_MFLIMIT) || (src_p + length > src_LASTLITERALS_3))
|
||||
{
|
||||
if (dst_cpy > dst_end) goto _output_error; // Error : writes beyond output buffer
|
||||
if (src_p + length != src_end) goto _output_error; // Error : LZ4 format requires to consume all input at this stage (no match within the last 11 bytes, and at least 8 remaining input bytes for another match+literals)
|
||||
BlockCopy(src_p, dst_p, (length));
|
||||
dst_p += length;
|
||||
break; // Necessarily EOF, due to parsing restrictions
|
||||
}
|
||||
do
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)src_p;
|
||||
dst_p += 4;
|
||||
src_p += 4;
|
||||
*(uint*)dst_p = *(uint*)src_p;
|
||||
dst_p += 4;
|
||||
src_p += 4;
|
||||
} while (dst_p < dst_cpy);
|
||||
src_p -= (dst_p - dst_cpy);
|
||||
dst_p = dst_cpy;
|
||||
|
||||
// get offset
|
||||
xxx_ref = (dst_cpy) - (*(ushort*)(src_p));
|
||||
src_p += 2;
|
||||
if (xxx_ref < dst) goto _output_error; // Error : offset outside of destination buffer
|
||||
|
||||
// get matchlength
|
||||
if ((length = (int)(xxx_token & ML_MASK)) == ML_MASK)
|
||||
{
|
||||
while (src_p < src_LASTLITERALS_1) // Error : a minimum input bytes must remain for LASTLITERALS + token
|
||||
{
|
||||
int s = *src_p++;
|
||||
length += s;
|
||||
if (s == 255) continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// copy repeated sequence
|
||||
if (dst_p - xxx_ref < STEPSIZE_32)
|
||||
{
|
||||
const int dec64 = 0;
|
||||
|
||||
dst_p[0] = xxx_ref[0];
|
||||
dst_p[1] = xxx_ref[1];
|
||||
dst_p[2] = xxx_ref[2];
|
||||
dst_p[3] = xxx_ref[3];
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
xxx_ref -= dec32table[dst_p - xxx_ref];
|
||||
(*(uint*)(dst_p)) = (*(uint*)(xxx_ref));
|
||||
dst_p += STEPSIZE_32 - 4;
|
||||
xxx_ref -= dec64;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
}
|
||||
dst_cpy = dst_p + length - (STEPSIZE_32 - 4);
|
||||
|
||||
if (dst_cpy > dst_COPYLENGTH_STEPSIZE_4)
|
||||
{
|
||||
if (dst_cpy > dst_LASTLITERALS) goto _output_error; // Error : last 5 bytes must be literals
|
||||
{
|
||||
do
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
} while (dst_p < dst_COPYLENGTH);
|
||||
}
|
||||
|
||||
while (dst_p < dst_cpy) *dst_p++ = *xxx_ref++;
|
||||
dst_p = dst_cpy;
|
||||
continue;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
} while (dst_p < dst_cpy);
|
||||
dst_p = dst_cpy; // correction
|
||||
}
|
||||
|
||||
// end of decoding
|
||||
return (int)((dst_p) - dst);
|
||||
|
||||
// write overflow error detected
|
||||
_output_error:
|
||||
return (int)(-((src_p) - src));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper restore JoinDeclarationAndInitializer
|
||||
// ReSharper restore TooWideLocalVariableScope
|
||||
// ReSharper restore InconsistentNaming
|
||||
+518
@@ -0,0 +1,518 @@
|
||||
#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 InconsistentNaming
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content.Pipeline.Utilities.LZ4
|
||||
{
|
||||
internal static partial class LZ4Codec
|
||||
{
|
||||
// Update chains up to ip (excluded)
|
||||
private static unsafe void LZ4HC_Insert_32(LZ4HC_Data_Structure hc4, byte* src_p)
|
||||
{
|
||||
fixed (ushort* chainTable = hc4.chainTable)
|
||||
fixed (int* hashTable = hc4.hashTable)
|
||||
{
|
||||
var src_base = hc4.src_base;
|
||||
|
||||
while (hc4.nextToUpdate < src_p)
|
||||
{
|
||||
var p = hc4.nextToUpdate;
|
||||
var delta = (int)((p) - (hashTable[((((*(uint*)(p))) * 2654435761u) >> HASHHC_ADJUST)] + src_base));
|
||||
if (delta > MAX_DISTANCE) delta = MAX_DISTANCE;
|
||||
chainTable[((int)p) & MAXD_MASK] = (ushort)delta;
|
||||
hashTable[((((*(uint*)(p))) * 2654435761u) >> HASHHC_ADJUST)] = (int)(p - src_base);
|
||||
hc4.nextToUpdate++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe int LZ4HC_CommonLength_32(byte* p1, byte* p2, byte* src_LASTLITERALS)
|
||||
{
|
||||
fixed (int* debruijn32 = DEBRUIJN_TABLE_32)
|
||||
{
|
||||
var p1t = p1;
|
||||
|
||||
while (p1t < src_LASTLITERALS - (STEPSIZE_32 - 1))
|
||||
{
|
||||
var diff = (*(int*)(p2)) ^ (*(int*)(p1t));
|
||||
if (diff == 0)
|
||||
{
|
||||
p1t += STEPSIZE_32;
|
||||
p2 += STEPSIZE_32;
|
||||
continue;
|
||||
}
|
||||
p1t += debruijn32[(((uint)((diff) & -(diff)) * 0x077CB531u)) >> 27];
|
||||
return (int)(p1t - p1);
|
||||
}
|
||||
if ((p1t < (src_LASTLITERALS - 1)) && ((*(ushort*)(p2)) == (*(ushort*)(p1t))))
|
||||
{
|
||||
p1t += 2;
|
||||
p2 += 2;
|
||||
}
|
||||
if ((p1t < src_LASTLITERALS) && (*p2 == *p1t)) p1t++;
|
||||
return (int)(p1t - p1);
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe int LZ4HC_InsertAndFindBestMatch_32(
|
||||
LZ4HC_Data_Structure hc4, byte* src_p, byte* src_LASTLITERALS, ref byte* matchpos)
|
||||
{
|
||||
fixed (ushort* chainTable = hc4.chainTable)
|
||||
fixed (int* hashTable = hc4.hashTable)
|
||||
{
|
||||
var src_base = hc4.src_base;
|
||||
var nbAttempts = MAX_NB_ATTEMPTS;
|
||||
int repl = 0, ml = 0;
|
||||
ushort delta = 0;
|
||||
|
||||
// HC4 match finder
|
||||
LZ4HC_Insert_32(hc4, src_p);
|
||||
var xxx_ref = (hashTable[((((*(uint*)(src_p))) * 2654435761u) >> HASHHC_ADJUST)] + src_base);
|
||||
|
||||
// Detect repetitive sequences of length <= 4
|
||||
if (xxx_ref >= src_p - 4) // potential repetition
|
||||
{
|
||||
if ((*(uint*)(xxx_ref)) == (*(uint*)(src_p))) // confirmed
|
||||
{
|
||||
delta = (ushort)(src_p - xxx_ref);
|
||||
repl = ml = LZ4HC_CommonLength_32(src_p + MINMATCH, xxx_ref + MINMATCH, src_LASTLITERALS) + MINMATCH;
|
||||
matchpos = xxx_ref;
|
||||
}
|
||||
xxx_ref = ((xxx_ref) - chainTable[((int)xxx_ref) & MAXD_MASK]);
|
||||
}
|
||||
|
||||
while ((xxx_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0))
|
||||
{
|
||||
nbAttempts--;
|
||||
if (*(xxx_ref + ml) == *(src_p + ml))
|
||||
if ((*(uint*)(xxx_ref)) == (*(uint*)(src_p)))
|
||||
{
|
||||
var mlt = LZ4HC_CommonLength_32(src_p + MINMATCH, xxx_ref + MINMATCH, src_LASTLITERALS) + MINMATCH;
|
||||
if (mlt > ml)
|
||||
{
|
||||
ml = mlt;
|
||||
matchpos = xxx_ref;
|
||||
}
|
||||
}
|
||||
xxx_ref = ((xxx_ref) - chainTable[((int)xxx_ref) & MAXD_MASK]);
|
||||
}
|
||||
|
||||
// Complete table
|
||||
if (repl != 0)
|
||||
{
|
||||
var src_ptr = src_p;
|
||||
|
||||
var src_end = src_p + repl - (MINMATCH - 1);
|
||||
while (src_ptr < src_end - delta)
|
||||
{
|
||||
chainTable[((int)src_ptr) & MAXD_MASK] = delta; // Pre-Load
|
||||
src_ptr++;
|
||||
}
|
||||
do
|
||||
{
|
||||
chainTable[((int)src_ptr) & MAXD_MASK] = delta;
|
||||
hashTable[((((*(uint*)(src_ptr))) * 2654435761u) >> HASHHC_ADJUST)] = (int)(src_ptr - src_base); // Head of chain
|
||||
src_ptr++;
|
||||
} while (src_ptr < src_end);
|
||||
hc4.nextToUpdate = src_end;
|
||||
}
|
||||
|
||||
return ml;
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe int LZ4HC_InsertAndGetWiderMatch_32(
|
||||
LZ4HC_Data_Structure hc4, byte* src_p, byte* startLimit, byte* src_LASTLITERALS, int longest,
|
||||
ref byte* matchpos, ref byte* startpos)
|
||||
{
|
||||
fixed (ushort* chainTable = hc4.chainTable)
|
||||
fixed (int* hashTable = hc4.hashTable)
|
||||
fixed (int* debruijn32 = DEBRUIJN_TABLE_32)
|
||||
{
|
||||
var src_base = hc4.src_base;
|
||||
var nbAttempts = MAX_NB_ATTEMPTS;
|
||||
var delta = (int)(src_p - startLimit);
|
||||
|
||||
// First Match
|
||||
LZ4HC_Insert_32(hc4, src_p);
|
||||
var xxx_ref = (hashTable[((((*(uint*)(src_p))) * 2654435761u) >> HASHHC_ADJUST)] + src_base);
|
||||
|
||||
while ((xxx_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0))
|
||||
{
|
||||
nbAttempts--;
|
||||
if (*(startLimit + longest) == *(xxx_ref - delta + longest))
|
||||
{
|
||||
if ((*(uint*)(xxx_ref)) == (*(uint*)(src_p)))
|
||||
{
|
||||
var reft = xxx_ref + MINMATCH;
|
||||
var ipt = src_p + MINMATCH;
|
||||
var startt = src_p;
|
||||
|
||||
while (ipt < src_LASTLITERALS - (STEPSIZE_32 - 1))
|
||||
{
|
||||
var diff = (*(int*)(reft)) ^ (*(int*)(ipt));
|
||||
if (diff == 0)
|
||||
{
|
||||
ipt += STEPSIZE_32;
|
||||
reft += STEPSIZE_32;
|
||||
continue;
|
||||
}
|
||||
ipt += debruijn32[(((uint)((diff) & -(diff)) * 0x077CB531u)) >> 27];
|
||||
goto _endCount;
|
||||
}
|
||||
if ((ipt < (src_LASTLITERALS - 1)) && ((*(ushort*)(reft)) == (*(ushort*)(ipt))))
|
||||
{
|
||||
ipt += 2;
|
||||
reft += 2;
|
||||
}
|
||||
if ((ipt < src_LASTLITERALS) && (*reft == *ipt)) ipt++;
|
||||
_endCount:
|
||||
reft = xxx_ref;
|
||||
|
||||
while ((startt > startLimit) && (reft > hc4.src_base) && (startt[-1] == reft[-1]))
|
||||
{
|
||||
startt--;
|
||||
reft--;
|
||||
}
|
||||
|
||||
if ((ipt - startt) > longest)
|
||||
{
|
||||
longest = (int)(ipt - startt);
|
||||
matchpos = reft;
|
||||
startpos = startt;
|
||||
}
|
||||
}
|
||||
}
|
||||
xxx_ref = ((xxx_ref) - chainTable[((int)xxx_ref) & MAXD_MASK]);
|
||||
}
|
||||
|
||||
return longest;
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe int LZ4_encodeSequence_32(
|
||||
ref byte* src_p, ref byte* dst_p, ref byte* src_anchor, int matchLength, byte* xxx_ref, byte* dst_end)
|
||||
{
|
||||
int len;
|
||||
|
||||
// Encode Literal length
|
||||
var length = (int)(src_p - src_anchor);
|
||||
var xxx_token = (dst_p)++;
|
||||
if ((dst_p + length + (2 + 1 + LASTLITERALS) + (length >> 8)) > dst_end) return 1; // Check output limit
|
||||
if (length >= RUN_MASK)
|
||||
{
|
||||
*xxx_token = (RUN_MASK << ML_BITS);
|
||||
len = length - RUN_MASK;
|
||||
for (; len > 254; len -= 255) *(dst_p)++ = 255;
|
||||
*(dst_p)++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*xxx_token = (byte)(length << ML_BITS);
|
||||
}
|
||||
|
||||
// Copy Literals
|
||||
var _p = dst_p + (length);
|
||||
do
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)src_anchor;
|
||||
dst_p += 4;
|
||||
src_anchor += 4;
|
||||
*(uint*)dst_p = *(uint*)src_anchor;
|
||||
dst_p += 4;
|
||||
src_anchor += 4;
|
||||
} while (dst_p < _p);
|
||||
dst_p = _p;
|
||||
|
||||
// Encode Offset
|
||||
*(ushort*)dst_p = (ushort)(src_p - xxx_ref);
|
||||
dst_p += 2;
|
||||
|
||||
// Encode MatchLength
|
||||
len = (matchLength - MINMATCH);
|
||||
if (dst_p + (1 + LASTLITERALS) + (length >> 8) > dst_end) return 1; // Check output limit
|
||||
if (len >= ML_MASK)
|
||||
{
|
||||
*xxx_token += ML_MASK;
|
||||
len -= ML_MASK;
|
||||
for (; len > 509; len -= 510)
|
||||
{
|
||||
*(dst_p)++ = 255;
|
||||
*(dst_p)++ = 255;
|
||||
}
|
||||
if (len > 254)
|
||||
{
|
||||
len -= 255;
|
||||
*(dst_p)++ = 255;
|
||||
}
|
||||
*(dst_p)++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*xxx_token += (byte)len;
|
||||
}
|
||||
|
||||
// Prepare next loop
|
||||
src_p += matchLength;
|
||||
src_anchor = src_p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static unsafe int LZ4_compressHCCtx_32(
|
||||
LZ4HC_Data_Structure ctx,
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
var src_p = src;
|
||||
var src_anchor = src_p;
|
||||
var src_end = src_p + src_len;
|
||||
var src_mflimit = src_end - MFLIMIT;
|
||||
var src_LASTLITERALS = (src_end - LASTLITERALS);
|
||||
|
||||
var dst_p = dst;
|
||||
var dst_end = dst_p + dst_maxlen;
|
||||
|
||||
byte* xxx_ref = null;
|
||||
byte* start2 = null;
|
||||
byte* ref2 = null;
|
||||
byte* start3 = null;
|
||||
byte* ref3 = null;
|
||||
|
||||
src_p++;
|
||||
|
||||
// Main Loop
|
||||
while (src_p < src_mflimit)
|
||||
{
|
||||
var ml = LZ4HC_InsertAndFindBestMatch_32(ctx, src_p, src_LASTLITERALS, ref xxx_ref);
|
||||
if (ml == 0)
|
||||
{
|
||||
src_p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// saved, in case we would skip too much
|
||||
var start0 = src_p;
|
||||
var ref0 = xxx_ref;
|
||||
var ml0 = ml;
|
||||
|
||||
_Search2:
|
||||
var ml2 = src_p + ml < src_mflimit
|
||||
? LZ4HC_InsertAndGetWiderMatch_32(ctx, src_p + ml - 2, src_p + 1, src_LASTLITERALS, ml, ref ref2, ref start2)
|
||||
: ml;
|
||||
|
||||
if (ml2 == ml) // No better match
|
||||
{
|
||||
if (LZ4_encodeSequence_32(ref src_p, ref dst_p, ref src_anchor, ml, xxx_ref, dst_end) != 0) return 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (start0 < src_p)
|
||||
{
|
||||
if (start2 < src_p + ml0) // empirical
|
||||
{
|
||||
src_p = start0;
|
||||
xxx_ref = ref0;
|
||||
ml = ml0;
|
||||
}
|
||||
}
|
||||
|
||||
// Here, start0==ip
|
||||
if ((start2 - src_p) < 3) // First Match too small : removed
|
||||
{
|
||||
ml = ml2;
|
||||
src_p = start2;
|
||||
xxx_ref = ref2;
|
||||
goto _Search2;
|
||||
}
|
||||
|
||||
_Search3:
|
||||
// Currently we have :
|
||||
// ml2 > ml1, and
|
||||
// ip1+3 <= ip2 (usually < ip1+ml1)
|
||||
if ((start2 - src_p) < OPTIMAL_ML)
|
||||
{
|
||||
var new_ml = ml;
|
||||
if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
|
||||
if (src_p + new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - src_p) + ml2 - MINMATCH;
|
||||
var correction = new_ml - (int)(start2 - src_p);
|
||||
if (correction > 0)
|
||||
{
|
||||
start2 += correction;
|
||||
ref2 += correction;
|
||||
ml2 -= correction;
|
||||
}
|
||||
}
|
||||
// Now, we have start2 = ip+new_ml, with new_ml=min(ml, OPTIMAL_ML=18)
|
||||
|
||||
var ml3 = start2 + ml2 < src_mflimit
|
||||
? LZ4HC_InsertAndGetWiderMatch_32(ctx, start2 + ml2 - 3, start2, src_LASTLITERALS, ml2, ref ref3, ref start3)
|
||||
: ml2;
|
||||
|
||||
if (ml3 == ml2) // No better match : 2 sequences to encode
|
||||
{
|
||||
// ip & ref are known; Now for ml
|
||||
if (start2 < src_p + ml) ml = (int)(start2 - src_p);
|
||||
// Now, encode 2 sequences
|
||||
if (LZ4_encodeSequence_32(ref src_p, ref dst_p, ref src_anchor, ml, xxx_ref, dst_end) != 0) return 0;
|
||||
src_p = start2;
|
||||
if (LZ4_encodeSequence_32(ref src_p, ref dst_p, ref src_anchor, ml2, ref2, dst_end) != 0) return 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (start3 < src_p + ml + 3) // Not enough space for match 2 : remove it
|
||||
{
|
||||
if (start3 >= (src_p + ml)) // can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1
|
||||
{
|
||||
if (start2 < src_p + ml)
|
||||
{
|
||||
var correction = (int)(src_p + ml - start2);
|
||||
start2 += correction;
|
||||
ref2 += correction;
|
||||
ml2 -= correction;
|
||||
if (ml2 < MINMATCH)
|
||||
{
|
||||
start2 = start3;
|
||||
ref2 = ref3;
|
||||
ml2 = ml3;
|
||||
}
|
||||
}
|
||||
|
||||
if (LZ4_encodeSequence_32(ref src_p, ref dst_p, ref src_anchor, ml, xxx_ref, dst_end) != 0) return 0;
|
||||
src_p = start3;
|
||||
xxx_ref = 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 < src_p + ml)
|
||||
{
|
||||
if ((start2 - src_p) < ML_MASK)
|
||||
{
|
||||
if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
|
||||
if (src_p + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - src_p) + ml2 - MINMATCH;
|
||||
var correction = ml - (int)(start2 - src_p);
|
||||
if (correction > 0)
|
||||
{
|
||||
start2 += correction;
|
||||
ref2 += correction;
|
||||
ml2 -= correction;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ml = (int)(start2 - src_p);
|
||||
}
|
||||
}
|
||||
if (LZ4_encodeSequence_32(ref src_p, ref dst_p, ref src_anchor, ml, xxx_ref, dst_end) != 0) return 0;
|
||||
|
||||
src_p = start2;
|
||||
xxx_ref = ref2;
|
||||
ml = ml2;
|
||||
|
||||
start2 = start3;
|
||||
ref2 = ref3;
|
||||
ml2 = ml3;
|
||||
|
||||
goto _Search3;
|
||||
}
|
||||
|
||||
// Encode Last Literals
|
||||
{
|
||||
var lastRun = (int)(src_end - src_anchor);
|
||||
if ((dst_p - dst) + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > (uint)dst_maxlen) return 0; // Check output limit
|
||||
if (lastRun >= RUN_MASK)
|
||||
{
|
||||
*dst_p++ = (RUN_MASK << ML_BITS);
|
||||
lastRun -= RUN_MASK;
|
||||
for (; lastRun > 254; lastRun -= 255) *dst_p++ = 255;
|
||||
*dst_p++ = (byte)lastRun;
|
||||
}
|
||||
else *dst_p++ = (byte)(lastRun << ML_BITS);
|
||||
BlockCopy(src_anchor, dst_p, (int)(src_end - src_anchor));
|
||||
dst_p += src_end - src_anchor;
|
||||
}
|
||||
|
||||
// End
|
||||
return (int)((dst_p) - dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
+814
@@ -0,0 +1,814 @@
|
||||
#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 InconsistentNaming
|
||||
// ReSharper disable TooWideLocalVariableScope
|
||||
// ReSharper disable JoinDeclarationAndInitializer
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content.Pipeline.Utilities.LZ4
|
||||
{
|
||||
internal static partial class LZ4Codec
|
||||
{
|
||||
#region LZ4_compressCtx_64
|
||||
|
||||
private static unsafe int LZ4_compressCtx_64(
|
||||
uint* hash_table,
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
byte* _p;
|
||||
|
||||
fixed (int* debruijn64 = &DEBRUIJN_TABLE_64[0])
|
||||
{
|
||||
// r93
|
||||
var src_p = src;
|
||||
var src_base = src_p;
|
||||
var src_anchor = src_p;
|
||||
var src_end = src_p + src_len;
|
||||
var src_mflimit = src_end - MFLIMIT;
|
||||
|
||||
var dst_p = dst;
|
||||
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[((((*(uint*)(src_p))) * 2654435761u) >> HASH_ADJUST)] = (uint)(src_p - src_base);
|
||||
src_p++;
|
||||
h_fwd = ((((*(uint*)(src_p))) * 2654435761u) >> HASH_ADJUST);
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
var findMatchAttempts = (1 << SKIPSTRENGTH) + 3;
|
||||
var src_p_fwd = src_p;
|
||||
byte* src_ref;
|
||||
byte* 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 = ((((*(uint*)(src_p_fwd))) * 2654435761u) >> HASH_ADJUST);
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (uint)(src_p - src_base);
|
||||
} while ((src_ref < src_p - MAX_DISTANCE) || ((*(uint*)(src_ref)) != (*(uint*)(src_p))));
|
||||
|
||||
// Catch up
|
||||
while ((src_p > src_anchor) && (src_ref > src) && (src_p[-1] == src_ref[-1]))
|
||||
{
|
||||
src_p--;
|
||||
src_ref--;
|
||||
}
|
||||
|
||||
// Encode Literal length
|
||||
length = (int)(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_token = (RUN_MASK << ML_BITS);
|
||||
if (len > 254)
|
||||
{
|
||||
do
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
len -= 255;
|
||||
} while (len > 254);
|
||||
*dst_p++ = (byte)len;
|
||||
BlockCopy(src_anchor, dst_p, (length));
|
||||
dst_p += length;
|
||||
goto _next_match;
|
||||
}
|
||||
*dst_p++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_token = (byte)(length << ML_BITS);
|
||||
}
|
||||
|
||||
// Copy Literals
|
||||
_p = dst_p + (length);
|
||||
{
|
||||
do
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)src_anchor;
|
||||
dst_p += 8;
|
||||
src_anchor += 8;
|
||||
} while (dst_p < _p);
|
||||
}
|
||||
dst_p = _p;
|
||||
|
||||
_next_match:
|
||||
|
||||
// Encode Offset
|
||||
*(ushort*)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*)(src_ref)) ^ (*(long*)(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) && ((*(uint*)(src_ref)) == (*(uint*)(src_p))))
|
||||
{
|
||||
src_p += 4;
|
||||
src_ref += 4;
|
||||
}
|
||||
if ((src_p < src_LASTLITERALS_1) && ((*(ushort*)(src_ref)) == (*(ushort*)(src_p))))
|
||||
{
|
||||
src_p += 2;
|
||||
src_ref += 2;
|
||||
}
|
||||
if ((src_p < src_LASTLITERALS) && (*src_ref == *src_p)) src_p++;
|
||||
|
||||
_endCount:
|
||||
|
||||
// Encode MatchLength
|
||||
length = (int)(src_p - src_anchor);
|
||||
|
||||
if (dst_p + (length >> 8) > dst_LASTLITERALS_1) return 0; // Check output limit
|
||||
|
||||
if (length >= ML_MASK)
|
||||
{
|
||||
*dst_token += ML_MASK;
|
||||
length -= ML_MASK;
|
||||
for (; length > 509; length -= 510)
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
if (length > 254)
|
||||
{
|
||||
length -= 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
*dst_p++ = (byte)length;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_token += (byte)length;
|
||||
}
|
||||
|
||||
// Test end of chunk
|
||||
if (src_p > src_mflimit)
|
||||
{
|
||||
src_anchor = src_p;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill table
|
||||
hash_table[((((*(uint*)(src_p - 2))) * 2654435761u) >> HASH_ADJUST)] = (uint)(src_p - 2 - src_base);
|
||||
|
||||
// Test next position
|
||||
|
||||
h = ((((*(uint*)(src_p))) * 2654435761u) >> HASH_ADJUST);
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (uint)(src_p - src_base);
|
||||
|
||||
if ((src_ref > src_p - (MAX_DISTANCE + 1)) && ((*(uint*)(src_ref)) == (*(uint*)(src_p))))
|
||||
{
|
||||
dst_token = dst_p++;
|
||||
*dst_token = 0;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
// Prepare next loop
|
||||
src_anchor = src_p++;
|
||||
h_fwd = ((((*(uint*)(src_p))) * 2654435761u) >> HASH_ADJUST);
|
||||
}
|
||||
|
||||
_last_literals:
|
||||
|
||||
// Encode Last Literals
|
||||
var lastRun = (int)(src_end - src_anchor);
|
||||
if (dst_p + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > dst_end) return 0;
|
||||
if (lastRun >= RUN_MASK)
|
||||
{
|
||||
*dst_p++ = (RUN_MASK << ML_BITS);
|
||||
lastRun -= RUN_MASK;
|
||||
for (; lastRun > 254; lastRun -= 255) *dst_p++ = 255;
|
||||
*dst_p++ = (byte)lastRun;
|
||||
}
|
||||
else *dst_p++ = (byte)(lastRun << ML_BITS);
|
||||
BlockCopy(src_anchor, dst_p, (int)(src_end - src_anchor));
|
||||
dst_p += src_end - src_anchor;
|
||||
|
||||
// End
|
||||
return (int)(dst_p - dst);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4_compress64kCtx_64
|
||||
|
||||
private static unsafe int LZ4_compress64kCtx_64(
|
||||
ushort* hash_table,
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
byte* _p;
|
||||
|
||||
fixed (int* debruijn64 = &DEBRUIJN_TABLE_64[0])
|
||||
{
|
||||
// r93
|
||||
var src_p = src;
|
||||
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;
|
||||
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 = ((((*(uint*)(src_p))) * 2654435761u) >> HASH64K_ADJUST);
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
var findMatchAttempts = (1 << SKIPSTRENGTH) + 3;
|
||||
var src_p_fwd = src_p;
|
||||
byte* src_ref;
|
||||
byte* 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 = ((((*(uint*)(src_p_fwd))) * 2654435761u) >> HASH64K_ADJUST);
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (ushort)(src_p - src_base);
|
||||
} while ((*(uint*)(src_ref)) != (*(uint*)(src_p)));
|
||||
|
||||
// Catch up
|
||||
while ((src_p > src_anchor) && (src_ref > src) && (src_p[-1] == src_ref[-1]))
|
||||
{
|
||||
src_p--;
|
||||
src_ref--;
|
||||
}
|
||||
|
||||
// Encode Literal length
|
||||
length = (int)(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_token = (RUN_MASK << ML_BITS);
|
||||
if (len > 254)
|
||||
{
|
||||
do
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
len -= 255;
|
||||
} while (len > 254);
|
||||
*dst_p++ = (byte)len;
|
||||
BlockCopy(src_anchor, dst_p, (length));
|
||||
dst_p += length;
|
||||
goto _next_match;
|
||||
}
|
||||
*dst_p++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_token = (byte)(length << ML_BITS);
|
||||
}
|
||||
|
||||
// Copy Literals
|
||||
{
|
||||
_p = dst_p + (length);
|
||||
{
|
||||
do
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)src_anchor;
|
||||
dst_p += 8;
|
||||
src_anchor += 8;
|
||||
} while (dst_p < _p);
|
||||
}
|
||||
dst_p = _p;
|
||||
}
|
||||
|
||||
_next_match:
|
||||
|
||||
// Encode Offset
|
||||
*(ushort*)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*)(src_ref)) ^ (*(long*)(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) && ((*(uint*)(src_ref)) == (*(uint*)(src_p))))
|
||||
{
|
||||
src_p += 4;
|
||||
src_ref += 4;
|
||||
}
|
||||
if ((src_p < src_LASTLITERALS_1) && ((*(ushort*)(src_ref)) == (*(ushort*)(src_p))))
|
||||
{
|
||||
src_p += 2;
|
||||
src_ref += 2;
|
||||
}
|
||||
if ((src_p < src_LASTLITERALS) && (*src_ref == *src_p)) src_p++;
|
||||
|
||||
_endCount:
|
||||
|
||||
// Encode MatchLength
|
||||
len = (int)(src_p - src_anchor);
|
||||
|
||||
if (dst_p + (len >> 8) > dst_LASTLITERALS_1) return 0; // Check output limit
|
||||
|
||||
if (len >= ML_MASK)
|
||||
{
|
||||
*dst_token += ML_MASK;
|
||||
len -= ML_MASK;
|
||||
for (; len > 509; len -= 510)
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
if (len > 254)
|
||||
{
|
||||
len -= 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
*dst_p++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_token += (byte)len;
|
||||
}
|
||||
|
||||
// Test end of chunk
|
||||
if (src_p > src_mflimit)
|
||||
{
|
||||
src_anchor = src_p;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill table
|
||||
hash_table[((((*(uint*)(src_p - 2))) * 2654435761u) >> HASH64K_ADJUST)] = (ushort)(src_p - 2 - src_base);
|
||||
|
||||
// Test next position
|
||||
|
||||
h = ((((*(uint*)(src_p))) * 2654435761u) >> HASH64K_ADJUST);
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (ushort)(src_p - src_base);
|
||||
|
||||
if ((*(uint*)(src_ref)) == (*(uint*)(src_p)))
|
||||
{
|
||||
dst_token = dst_p++;
|
||||
*dst_token = 0;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
// Prepare next loop
|
||||
src_anchor = src_p++;
|
||||
h_fwd = ((((*(uint*)(src_p))) * 2654435761u) >> HASH64K_ADJUST);
|
||||
}
|
||||
|
||||
_last_literals:
|
||||
|
||||
// Encode Last Literals
|
||||
var lastRun = (int)(src_end - src_anchor);
|
||||
if (dst_p + lastRun + 1 + (lastRun - RUN_MASK + 255) / 255 > dst_end) return 0;
|
||||
if (lastRun >= RUN_MASK)
|
||||
{
|
||||
*dst_p++ = (RUN_MASK << ML_BITS);
|
||||
lastRun -= RUN_MASK;
|
||||
for (; lastRun > 254; lastRun -= 255) *dst_p++ = 255;
|
||||
*dst_p++ = (byte)lastRun;
|
||||
}
|
||||
else *dst_p++ = (byte)(lastRun << ML_BITS);
|
||||
BlockCopy(src_anchor, dst_p, (int)(src_end - src_anchor));
|
||||
dst_p += src_end - src_anchor;
|
||||
|
||||
// End
|
||||
return (int)(dst_p - dst);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4_uncompress_64
|
||||
|
||||
private static unsafe int LZ4_uncompress_64(
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int dst_len)
|
||||
{
|
||||
fixed (int* dec32table = &DECODER_TABLE_32[0])
|
||||
fixed (int* dec64table = &DECODER_TABLE_64[0])
|
||||
{
|
||||
// r93
|
||||
var src_p = src;
|
||||
byte* dst_ref;
|
||||
|
||||
var dst_p = dst;
|
||||
var dst_end = dst_p + dst_len;
|
||||
byte* 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);
|
||||
|
||||
byte token;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
int length;
|
||||
|
||||
// get runlength
|
||||
token = *src_p++;
|
||||
if ((length = (token >> ML_BITS)) == RUN_MASK)
|
||||
{
|
||||
int len;
|
||||
for (; (len = *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_p, dst_p, (length));
|
||||
src_p += length;
|
||||
break; // EOF
|
||||
}
|
||||
do
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)src_p;
|
||||
dst_p += 8;
|
||||
src_p += 8;
|
||||
} while (dst_p < dst_cpy);
|
||||
src_p -= (dst_p - dst_cpy);
|
||||
dst_p = dst_cpy;
|
||||
|
||||
// get offset
|
||||
dst_ref = (dst_cpy) - (*(ushort*)(src_p));
|
||||
src_p += 2;
|
||||
if (dst_ref < dst) goto _output_error; // Error : offset outside destination buffer
|
||||
|
||||
// get matchlength
|
||||
if ((length = (token & ML_MASK)) == ML_MASK)
|
||||
{
|
||||
for (; *src_p == 255; length += 255) src_p++;
|
||||
length += *src_p++;
|
||||
}
|
||||
|
||||
// copy repeated sequence
|
||||
if ((dst_p - dst_ref) < STEPSIZE_64)
|
||||
{
|
||||
var dec64 = dec64table[dst_p - dst_ref];
|
||||
|
||||
dst_p[0] = dst_ref[0];
|
||||
dst_p[1] = dst_ref[1];
|
||||
dst_p[2] = dst_ref[2];
|
||||
dst_p[3] = dst_ref[3];
|
||||
dst_p += 4;
|
||||
dst_ref += 4;
|
||||
dst_ref -= dec32table[dst_p - dst_ref];
|
||||
(*(uint*)(dst_p)) = (*(uint*)(dst_ref));
|
||||
dst_p += STEPSIZE_64 - 4;
|
||||
dst_ref -= dec64;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)dst_ref;
|
||||
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
|
||||
while (dst_p < dst_COPYLENGTH)
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)dst_ref;
|
||||
dst_p += 8;
|
||||
dst_ref += 8;
|
||||
}
|
||||
|
||||
while (dst_p < dst_cpy) *dst_p++ = *dst_ref++;
|
||||
dst_p = dst_cpy;
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
do
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)dst_ref;
|
||||
dst_p += 8;
|
||||
dst_ref += 8;
|
||||
} while (dst_p < dst_cpy);
|
||||
}
|
||||
dst_p = dst_cpy; // correction
|
||||
}
|
||||
|
||||
// end of decoding
|
||||
return (int)((src_p) - src);
|
||||
|
||||
// write overflow error detected
|
||||
_output_error:
|
||||
return (int)(-((src_p) - src));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4_uncompress_unknownOutputSize_64
|
||||
|
||||
private static unsafe int LZ4_uncompress_unknownOutputSize_64(
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
fixed (int* dec32table = &DECODER_TABLE_32[0])
|
||||
fixed (int* dec64table = &DECODER_TABLE_64[0])
|
||||
{
|
||||
// r93
|
||||
var src_p = src;
|
||||
var src_end = src_p + src_len;
|
||||
byte* dst_ref;
|
||||
|
||||
var dst_p = dst;
|
||||
var dst_end = dst_p + dst_maxlen;
|
||||
byte* dst_cpy;
|
||||
|
||||
var src_LASTLITERALS_3 = (src_end - (2 + 1 + LASTLITERALS));
|
||||
var src_LASTLITERALS_1 = (src_end - (LASTLITERALS + 1));
|
||||
var dst_COPYLENGTH = (dst_end - COPYLENGTH);
|
||||
var dst_COPYLENGTH_STEPSIZE_4 = (dst_end - (COPYLENGTH + (STEPSIZE_64 - 4)));
|
||||
var dst_LASTLITERALS = (dst_end - LASTLITERALS);
|
||||
var dst_MFLIMIT = (dst_end - MFLIMIT);
|
||||
|
||||
// Special case
|
||||
if (src_p == src_end) goto _output_error; // A correctly formed null-compressed LZ4 must have at least one byte (token=0)
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
byte token;
|
||||
int length;
|
||||
|
||||
// get runlength
|
||||
token = *src_p++;
|
||||
if ((length = (token >> ML_BITS)) == RUN_MASK)
|
||||
{
|
||||
var s = 255;
|
||||
while ((src_p < src_end) && (s == 255))
|
||||
{
|
||||
s = *src_p++;
|
||||
length += s;
|
||||
}
|
||||
}
|
||||
|
||||
// copy literals
|
||||
dst_cpy = dst_p + length;
|
||||
|
||||
if ((dst_cpy > dst_MFLIMIT) || (src_p + length > src_LASTLITERALS_3))
|
||||
{
|
||||
if (dst_cpy > dst_end) goto _output_error; // Error : writes beyond output buffer
|
||||
if (src_p + length != src_end) goto _output_error; // Error : LZ4 format requires to consume all input at this stage (no match within the last 11 bytes, and at least 8 remaining input bytes for another match+literals)
|
||||
BlockCopy(src_p, dst_p, (length));
|
||||
dst_p += length;
|
||||
break; // Necessarily EOF, due to parsing restrictions
|
||||
}
|
||||
do
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)src_p;
|
||||
dst_p += 8;
|
||||
src_p += 8;
|
||||
} while (dst_p < dst_cpy);
|
||||
src_p -= (dst_p - dst_cpy);
|
||||
dst_p = dst_cpy;
|
||||
|
||||
// get offset
|
||||
dst_ref = (dst_cpy) - (*(ushort*)(src_p));
|
||||
src_p += 2;
|
||||
if (dst_ref < dst) goto _output_error; // Error : offset outside of destination buffer
|
||||
|
||||
// get matchlength
|
||||
if ((length = (token & ML_MASK)) == ML_MASK)
|
||||
{
|
||||
while (src_p < src_LASTLITERALS_1) // Error : a minimum input bytes must remain for LASTLITERALS + token
|
||||
{
|
||||
int s = *src_p++;
|
||||
length += s;
|
||||
if (s == 255) continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// copy repeated sequence
|
||||
if (dst_p - dst_ref < STEPSIZE_64)
|
||||
{
|
||||
var dec64 = dec64table[dst_p - dst_ref];
|
||||
|
||||
dst_p[0] = dst_ref[0];
|
||||
dst_p[1] = dst_ref[1];
|
||||
dst_p[2] = dst_ref[2];
|
||||
dst_p[3] = dst_ref[3];
|
||||
dst_p += 4;
|
||||
dst_ref += 4;
|
||||
dst_ref -= dec32table[dst_p - dst_ref];
|
||||
(*(uint*)(dst_p)) = (*(uint*)(dst_ref));
|
||||
dst_p += STEPSIZE_64 - 4;
|
||||
dst_ref -= dec64;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)dst_ref;
|
||||
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
|
||||
while (dst_p < dst_COPYLENGTH)
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)dst_ref;
|
||||
dst_p += 8;
|
||||
dst_ref += 8;
|
||||
}
|
||||
|
||||
while (dst_p < dst_cpy) *dst_p++ = *dst_ref++;
|
||||
dst_p = dst_cpy;
|
||||
continue;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)dst_ref;
|
||||
dst_p += 8;
|
||||
dst_ref += 8;
|
||||
} while (dst_p < dst_cpy);
|
||||
dst_p = dst_cpy; // correction
|
||||
}
|
||||
|
||||
// end of decoding
|
||||
return (int)(dst_p - dst);
|
||||
|
||||
_output_error:
|
||||
|
||||
// write overflow error detected
|
||||
return (int)-(src_p - src);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper restore JoinDeclarationAndInitializer
|
||||
// ReSharper restore TooWideLocalVariableScope
|
||||
// ReSharper restore InconsistentNaming
|
||||
+527
@@ -0,0 +1,527 @@
|
||||
#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 InconsistentNaming
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content.Pipeline.Utilities.LZ4
|
||||
{
|
||||
internal static partial class LZ4Codec
|
||||
{
|
||||
// Update chains up to ip (excluded)
|
||||
private static unsafe void LZ4HC_Insert_64(LZ4HC_Data_Structure hc4, byte* src_p)
|
||||
{
|
||||
fixed (ushort* chainTable = hc4.chainTable)
|
||||
fixed (int* hashTable = hc4.hashTable)
|
||||
{
|
||||
var src_base = hc4.src_base;
|
||||
while (hc4.nextToUpdate < src_p)
|
||||
{
|
||||
var p = hc4.nextToUpdate;
|
||||
var delta = (int)((p) - (hashTable[((((*(uint*)(p))) * 2654435761u) >> HASHHC_ADJUST)] + src_base));
|
||||
if (delta > MAX_DISTANCE) delta = MAX_DISTANCE;
|
||||
chainTable[((int)p) & MAXD_MASK] = (ushort)delta;
|
||||
hashTable[((((*(uint*)(p))) * 2654435761u) >> HASHHC_ADJUST)] = (int)(p - src_base);
|
||||
hc4.nextToUpdate++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe int LZ4HC_CommonLength_64(byte* p1, byte* p2, byte* src_LASTLITERALS)
|
||||
{
|
||||
fixed (int* debruijn64 = DEBRUIJN_TABLE_64)
|
||||
{
|
||||
var p1t = p1;
|
||||
|
||||
while (p1t < src_LASTLITERALS - (STEPSIZE_64 - 1))
|
||||
{
|
||||
var diff = (*(long*)(p2)) ^ (*(long*)(p1t));
|
||||
if (diff == 0)
|
||||
{
|
||||
p1t += STEPSIZE_64;
|
||||
p2 += STEPSIZE_64;
|
||||
continue;
|
||||
}
|
||||
p1t += debruijn64[(((ulong)((diff) & -(diff)) * 0x0218A392CDABBD3FL)) >> 58];
|
||||
return (int)(p1t - p1);
|
||||
}
|
||||
if ((p1t < (src_LASTLITERALS - 3)) && ((*(uint*)(p2)) == (*(uint*)(p1t))))
|
||||
{
|
||||
p1t += 4;
|
||||
p2 += 4;
|
||||
}
|
||||
if ((p1t < (src_LASTLITERALS - 1)) && ((*(ushort*)(p2)) == (*(ushort*)(p1t))))
|
||||
{
|
||||
p1t += 2;
|
||||
p2 += 2;
|
||||
}
|
||||
if ((p1t < src_LASTLITERALS) && (*p2 == *p1t)) p1t++;
|
||||
return (int)(p1t - p1);
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe int LZ4HC_InsertAndFindBestMatch_64(
|
||||
LZ4HC_Data_Structure hc4, byte* src_p, byte* src_LASTLITERALS, ref byte* matchpos)
|
||||
{
|
||||
fixed (ushort* chainTable = hc4.chainTable)
|
||||
fixed (int* hashTable = hc4.hashTable)
|
||||
{
|
||||
var src_base = hc4.src_base;
|
||||
var nbAttempts = MAX_NB_ATTEMPTS;
|
||||
int repl = 0, ml = 0;
|
||||
ushort delta = 0;
|
||||
|
||||
// HC4 match finder
|
||||
LZ4HC_Insert_64(hc4, src_p);
|
||||
var src_ref = (hashTable[((((*(uint*)(src_p))) * 2654435761u) >> HASHHC_ADJUST)] + src_base);
|
||||
|
||||
// Detect repetitive sequences of length <= 4
|
||||
if (src_ref >= src_p - 4) // potential repetition
|
||||
{
|
||||
if ((*(uint*)(src_ref)) == (*(uint*)(src_p))) // confirmed
|
||||
{
|
||||
delta = (ushort)(src_p - src_ref);
|
||||
repl = ml = LZ4HC_CommonLength_64(src_p + MINMATCH, src_ref + MINMATCH, src_LASTLITERALS) + MINMATCH;
|
||||
matchpos = src_ref;
|
||||
}
|
||||
src_ref = ((src_ref) - chainTable[((int)src_ref) & MAXD_MASK]);
|
||||
}
|
||||
|
||||
while ((src_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0))
|
||||
{
|
||||
nbAttempts--;
|
||||
if (*(src_ref + ml) == *(src_p + ml))
|
||||
if ((*(uint*)(src_ref)) == (*(uint*)(src_p)))
|
||||
{
|
||||
var mlt = LZ4HC_CommonLength_64(src_p + MINMATCH, src_ref + MINMATCH, src_LASTLITERALS) + MINMATCH;
|
||||
if (mlt > ml)
|
||||
{
|
||||
ml = mlt;
|
||||
matchpos = src_ref;
|
||||
}
|
||||
}
|
||||
src_ref = ((src_ref) - chainTable[((int)src_ref) & MAXD_MASK]);
|
||||
}
|
||||
|
||||
// Complete table
|
||||
if (repl != 0)
|
||||
{
|
||||
var ptr = src_p;
|
||||
|
||||
var end = src_p + repl - (MINMATCH - 1);
|
||||
while (ptr < end - delta)
|
||||
{
|
||||
chainTable[((int)ptr) & MAXD_MASK] = delta; // Pre-Load
|
||||
ptr++;
|
||||
}
|
||||
do
|
||||
{
|
||||
chainTable[((int)ptr) & MAXD_MASK] = delta;
|
||||
hashTable[((((*(uint*)(ptr))) * 2654435761u) >> HASHHC_ADJUST)] = (int)(ptr - src_base); // Head of chain
|
||||
ptr++;
|
||||
} while (ptr < end);
|
||||
hc4.nextToUpdate = end;
|
||||
}
|
||||
|
||||
return ml;
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe int LZ4HC_InsertAndGetWiderMatch_64(
|
||||
LZ4HC_Data_Structure hc4, byte* src_p, byte* startLimit, byte* src_LASTLITERALS, int longest,
|
||||
ref byte* matchpos, ref byte* startpos)
|
||||
{
|
||||
fixed (ushort* chainTable = hc4.chainTable)
|
||||
fixed (int* hashTable = hc4.hashTable)
|
||||
fixed (int* debruijn64 = DEBRUIJN_TABLE_64)
|
||||
{
|
||||
var src_base = hc4.src_base;
|
||||
var nbAttempts = MAX_NB_ATTEMPTS;
|
||||
var delta = (int)(src_p - startLimit);
|
||||
|
||||
// First Match
|
||||
LZ4HC_Insert_64(hc4, src_p);
|
||||
var src_ref = (hashTable[((((*(uint*)(src_p))) * 2654435761u) >> HASHHC_ADJUST)] + src_base);
|
||||
|
||||
while ((src_ref >= src_p - MAX_DISTANCE) && (nbAttempts != 0))
|
||||
{
|
||||
nbAttempts--;
|
||||
if (*(startLimit + longest) == *(src_ref - delta + longest))
|
||||
{
|
||||
if ((*(uint*)(src_ref)) == (*(uint*)(src_p)))
|
||||
{
|
||||
var reft = src_ref + MINMATCH;
|
||||
var ipt = src_p + MINMATCH;
|
||||
var startt = src_p;
|
||||
|
||||
while (ipt < src_LASTLITERALS - (STEPSIZE_64 - 1))
|
||||
{
|
||||
var diff = (*(long*)(reft)) ^ (*(long*)(ipt));
|
||||
if (diff == 0)
|
||||
{
|
||||
ipt += STEPSIZE_64;
|
||||
reft += STEPSIZE_64;
|
||||
continue;
|
||||
}
|
||||
ipt += debruijn64[(((ulong)((diff) & -(diff)) * 0x0218A392CDABBD3FL)) >> 58];
|
||||
goto _endCount;
|
||||
}
|
||||
if ((ipt < (src_LASTLITERALS - 3)) && ((*(uint*)(reft)) == (*(uint*)(ipt))))
|
||||
{
|
||||
ipt += 4;
|
||||
reft += 4;
|
||||
}
|
||||
if ((ipt < (src_LASTLITERALS - 1)) && ((*(ushort*)(reft)) == (*(ushort*)(ipt))))
|
||||
{
|
||||
ipt += 2;
|
||||
reft += 2;
|
||||
}
|
||||
if ((ipt < src_LASTLITERALS) && (*reft == *ipt)) ipt++;
|
||||
|
||||
_endCount:
|
||||
reft = src_ref;
|
||||
|
||||
while ((startt > startLimit) && (reft > hc4.src_base) && (startt[-1] == reft[-1]))
|
||||
{
|
||||
startt--;
|
||||
reft--;
|
||||
}
|
||||
|
||||
if ((ipt - startt) > longest)
|
||||
{
|
||||
longest = (int)(ipt - startt);
|
||||
matchpos = reft;
|
||||
startpos = startt;
|
||||
}
|
||||
}
|
||||
}
|
||||
src_ref = ((src_ref) - chainTable[((int)src_ref) & MAXD_MASK]);
|
||||
}
|
||||
|
||||
return longest;
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe int LZ4_encodeSequence_64(
|
||||
ref byte* src_p, ref byte* dst_p, ref byte* src_anchor, int matchLength, byte* src_ref, byte* dst_end)
|
||||
{
|
||||
int len;
|
||||
var dst_token = (dst_p)++;
|
||||
|
||||
// Encode Literal length
|
||||
var length = (int)(src_p - src_anchor);
|
||||
if ((dst_p + length + (2 + 1 + LASTLITERALS) + (length >> 8)) > dst_end) return 1; // Check output limit
|
||||
if (length >= RUN_MASK)
|
||||
{
|
||||
*dst_token = (RUN_MASK << ML_BITS);
|
||||
len = length - RUN_MASK;
|
||||
for (; len > 254; len -= 255) *(dst_p)++ = 255;
|
||||
*(dst_p)++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_token = (byte)(length << ML_BITS);
|
||||
}
|
||||
|
||||
// Copy Literals
|
||||
var _p = dst_p + (length);
|
||||
do
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)src_anchor;
|
||||
dst_p += 8;
|
||||
src_anchor += 8;
|
||||
} while (dst_p < _p);
|
||||
dst_p = _p;
|
||||
|
||||
// Encode Offset
|
||||
*(ushort*)dst_p = (ushort)(src_p - src_ref);
|
||||
dst_p += 2;
|
||||
|
||||
// Encode MatchLength
|
||||
len = (matchLength - MINMATCH);
|
||||
if (dst_p + (1 + LASTLITERALS) + (length >> 8) > dst_end) return 1; // Check output limit
|
||||
if (len >= ML_MASK)
|
||||
{
|
||||
*dst_token += ML_MASK;
|
||||
len -= ML_MASK;
|
||||
for (; len > 509; len -= 510)
|
||||
{
|
||||
*(dst_p)++ = 255;
|
||||
*(dst_p)++ = 255;
|
||||
}
|
||||
if (len > 254)
|
||||
{
|
||||
len -= 255;
|
||||
*(dst_p)++ = 255;
|
||||
}
|
||||
*(dst_p)++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_token += (byte)len;
|
||||
}
|
||||
|
||||
// Prepare next loop
|
||||
src_p += matchLength;
|
||||
src_anchor = src_p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static unsafe int LZ4_compressHCCtx_64(
|
||||
LZ4HC_Data_Structure ctx,
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
var src_p = src;
|
||||
var src_anchor = src_p;
|
||||
var src_end = src_p + src_len;
|
||||
var src_mflimit = src_end - MFLIMIT;
|
||||
var src_LASTLITERALS = (src_end - LASTLITERALS);
|
||||
|
||||
var dst_p = dst;
|
||||
var dst_end = dst_p + dst_maxlen;
|
||||
|
||||
byte* src_ref = null;
|
||||
byte* start2 = null;
|
||||
byte* ref2 = null;
|
||||
byte* start3 = null;
|
||||
byte* ref3 = null;
|
||||
|
||||
src_p++;
|
||||
|
||||
// Main Loop
|
||||
while (src_p < src_mflimit)
|
||||
{
|
||||
var ml = LZ4HC_InsertAndFindBestMatch_64(ctx, src_p, src_LASTLITERALS, ref src_ref);
|
||||
if (ml == 0)
|
||||
{
|
||||
src_p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// saved, in case we would skip too much
|
||||
var start0 = src_p;
|
||||
var ref0 = src_ref;
|
||||
var ml0 = ml;
|
||||
|
||||
_Search2:
|
||||
var ml2 = src_p + ml < src_mflimit
|
||||
? LZ4HC_InsertAndGetWiderMatch_64(ctx, src_p + ml - 2, src_p + 1, src_LASTLITERALS, ml, ref ref2, ref start2)
|
||||
: ml;
|
||||
|
||||
if (ml2 == ml) // No better match
|
||||
{
|
||||
if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) return 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (start0 < src_p && start2 < src_p + ml0)
|
||||
{
|
||||
src_p = start0;
|
||||
src_ref = ref0;
|
||||
ml = ml0;
|
||||
}
|
||||
|
||||
// Here, start0==ip
|
||||
if ((start2 - src_p) < 3) // First Match too small : removed
|
||||
{
|
||||
ml = ml2;
|
||||
src_p = start2;
|
||||
src_ref = ref2;
|
||||
goto _Search2;
|
||||
}
|
||||
|
||||
_Search3:
|
||||
// Currently we have :
|
||||
// ml2 > ml1, and
|
||||
// ip1+3 <= ip2 (usually < ip1+ml1)
|
||||
if ((start2 - src_p) < OPTIMAL_ML)
|
||||
{
|
||||
var new_ml = ml;
|
||||
if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
|
||||
if (src_p + new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - src_p) + ml2 - MINMATCH;
|
||||
var correction = new_ml - (int)(start2 - src_p);
|
||||
if (correction > 0)
|
||||
{
|
||||
start2 += correction;
|
||||
ref2 += correction;
|
||||
ml2 -= correction;
|
||||
}
|
||||
}
|
||||
|
||||
// Now, we have start2 = ip+new_ml, with new_ml=min(ml, OPTIMAL_ML=18)
|
||||
|
||||
var ml3 = start2 + ml2 < src_mflimit
|
||||
? LZ4HC_InsertAndGetWiderMatch_64(ctx, start2 + ml2 - 3, start2, src_LASTLITERALS, ml2, ref ref3, ref start3)
|
||||
: ml2;
|
||||
|
||||
if (ml3 == ml2) // No better match : 2 sequences to encode
|
||||
{
|
||||
// ip & ref are known; Now for ml
|
||||
if (start2 < src_p + ml) ml = (int)(start2 - src_p);
|
||||
|
||||
// Now, encode 2 sequences
|
||||
if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) return 0;
|
||||
src_p = start2;
|
||||
if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml2, ref2, dst_end) != 0) return 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (start3 < src_p + ml + 3) // Not enough space for match 2 : remove it
|
||||
{
|
||||
if (start3 >= src_p + ml) // can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1
|
||||
{
|
||||
if (start2 < src_p + ml)
|
||||
{
|
||||
var correction = (int)(src_p + ml - start2);
|
||||
start2 += correction;
|
||||
ref2 += correction;
|
||||
ml2 -= correction;
|
||||
if (ml2 < MINMATCH)
|
||||
{
|
||||
start2 = start3;
|
||||
ref2 = ref3;
|
||||
ml2 = ml3;
|
||||
}
|
||||
}
|
||||
|
||||
if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0) return 0;
|
||||
src_p = start3;
|
||||
src_ref = 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 < src_p + ml)
|
||||
{
|
||||
if (start2 - src_p < ML_MASK)
|
||||
{
|
||||
if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
|
||||
if (src_p + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - src_p) + ml2 - MINMATCH;
|
||||
var correction = ml - (int)(start2 - src_p);
|
||||
if (correction > 0)
|
||||
{
|
||||
start2 += correction;
|
||||
ref2 += correction;
|
||||
ml2 -= correction;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ml = (int)(start2 - src_p);
|
||||
}
|
||||
}
|
||||
|
||||
if (LZ4_encodeSequence_64(ref src_p, ref dst_p, ref src_anchor, ml, src_ref, dst_end) != 0)
|
||||
return 0;
|
||||
|
||||
src_p = start2;
|
||||
src_ref = ref2;
|
||||
ml = ml2;
|
||||
|
||||
start2 = start3;
|
||||
ref2 = ref3;
|
||||
ml2 = ml3;
|
||||
|
||||
goto _Search3;
|
||||
}
|
||||
|
||||
// Encode Last Literals
|
||||
var lastRun = (int)(src_end - src_anchor);
|
||||
if ((dst_p - dst) + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > (uint)dst_maxlen) return 0; // Check output limit
|
||||
if (lastRun >= RUN_MASK)
|
||||
{
|
||||
*dst_p++ = (RUN_MASK << ML_BITS);
|
||||
lastRun -= RUN_MASK;
|
||||
for (; lastRun > 254; lastRun -= 255) *dst_p++ = 255;
|
||||
*dst_p++ = (byte)lastRun;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_p++ = (byte)(lastRun << ML_BITS);
|
||||
}
|
||||
BlockCopy(src_anchor, dst_p, (int)(src_end - src_anchor));
|
||||
dst_p += src_end - src_anchor;
|
||||
|
||||
// End
|
||||
return (int)((dst_p) - dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
#region license
|
||||
|
||||
/*
|
||||
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
|
||||
|
||||
using System;
|
||||
|
||||
/*
|
||||
NOTE:
|
||||
This file is shared between LZ4n and LZ4s.
|
||||
If you would like to modify this file please keep in mind that your changes will
|
||||
affect both projects.
|
||||
Use 'LZ4s' conditional define to differentiate
|
||||
*/
|
||||
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content.Pipeline.Utilities.LZ4
|
||||
{
|
||||
internal static partial class LZ4Codec
|
||||
{
|
||||
#region configuration
|
||||
|
||||
/// <summary>
|
||||
/// Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
|
||||
/// Increasing memory usage improves compression ratio
|
||||
/// Reduced memory usage can improve speed, due to cache effect
|
||||
/// Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
|
||||
/// </summary>
|
||||
private const int MEMORY_USAGE = 14;
|
||||
|
||||
/// <summary>
|
||||
/// Decreasing this value will make the algorithm skip faster data segments considered "incompressible"
|
||||
/// This may decrease compression ratio dramatically, but will be faster on incompressible data
|
||||
/// Increasing this value will make the algorithm search more before declaring a segment "incompressible"
|
||||
/// This could improve compression a bit, but will be slower on incompressible data
|
||||
/// The default value (6) is recommended
|
||||
/// </summary>
|
||||
private const int NOTCOMPRESSIBLE_DETECTIONLEVEL = 6;
|
||||
|
||||
#if LZ4s
|
||||
|
||||
/// <summary>Buffer length when Buffer.BlockCopy becomes faster than straight loop.
|
||||
/// Please note that safe implementation REQUIRES it to be greater (not even equal) than 8.</summary>
|
||||
private const int BLOCK_COPY_LIMIT = 16;
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region consts
|
||||
|
||||
private const int MINMATCH = 4;
|
||||
#pragma warning disable 162
|
||||
private const int SKIPSTRENGTH = NOTCOMPRESSIBLE_DETECTIONLEVEL > 2 ? NOTCOMPRESSIBLE_DETECTIONLEVEL : 2;
|
||||
#pragma warning restore 162
|
||||
private const int COPYLENGTH = 8;
|
||||
private const int LASTLITERALS = 5;
|
||||
private const int MFLIMIT = COPYLENGTH + MINMATCH;
|
||||
private const int MINLENGTH = MFLIMIT + 1;
|
||||
private const int MAXD_LOG = 16;
|
||||
private const int MAXD = 1 << MAXD_LOG;
|
||||
private const int MAXD_MASK = MAXD - 1;
|
||||
private const int MAX_DISTANCE = (1 << MAXD_LOG) - 1;
|
||||
private const int ML_BITS = 4;
|
||||
private const int ML_MASK = (1 << ML_BITS) - 1;
|
||||
private const int RUN_BITS = 8 - ML_BITS;
|
||||
private const int RUN_MASK = (1 << RUN_BITS) - 1;
|
||||
private const int STEPSIZE_64 = 8;
|
||||
private const int STEPSIZE_32 = 4;
|
||||
|
||||
private const int LZ4_64KLIMIT = (1 << 16) + (MFLIMIT - 1);
|
||||
|
||||
private const int HASH_LOG = MEMORY_USAGE - 2;
|
||||
private const int HASH_TABLESIZE = 1 << HASH_LOG;
|
||||
private const int HASH_ADJUST = (MINMATCH * 8) - HASH_LOG;
|
||||
|
||||
private const int HASH64K_LOG = HASH_LOG + 1;
|
||||
private const int HASH64K_TABLESIZE = 1 << HASH64K_LOG;
|
||||
private const int HASH64K_ADJUST = (MINMATCH * 8) - HASH64K_LOG;
|
||||
|
||||
private const int HASHHC_LOG = MAXD_LOG - 1;
|
||||
private const int HASHHC_TABLESIZE = 1 << HASHHC_LOG;
|
||||
private const int HASHHC_ADJUST = (MINMATCH * 8) - HASHHC_LOG;
|
||||
//private const int HASHHC_MASK = HASHHC_TABLESIZE - 1;
|
||||
|
||||
private static readonly int[] DECODER_TABLE_32 = new[] { 0, 3, 2, 3, 0, 0, 0, 0 };
|
||||
private static readonly int[] DECODER_TABLE_64 = new[] { 0, 0, 0, -1, 0, 1, 2, 3 };
|
||||
|
||||
private static readonly int[] DEBRUIJN_TABLE_32 = new[] {
|
||||
0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1,
|
||||
3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1
|
||||
};
|
||||
|
||||
private static readonly int[] DEBRUIJN_TABLE_64 = new[] {
|
||||
0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7,
|
||||
0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7,
|
||||
7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6,
|
||||
7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7
|
||||
};
|
||||
|
||||
private const int MAX_NB_ATTEMPTS = 256;
|
||||
private const int OPTIMAL_ML = (ML_MASK - 1) + MINMATCH;
|
||||
|
||||
#endregion
|
||||
|
||||
#region public interface (common)
|
||||
|
||||
/// <summary>Gets maximum the length of the output.</summary>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <returns>Maximum number of bytes needed for compressed buffer.</returns>
|
||||
public static int MaximumOutputLength(int inputLength)
|
||||
{
|
||||
return inputLength + (inputLength / 255) + 16;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region internal interface (common)
|
||||
|
||||
internal static void CheckArguments(
|
||||
byte[] input, int inputOffset, ref int inputLength,
|
||||
byte[] output, int outputOffset, ref int outputLength)
|
||||
{
|
||||
if (inputLength < 0) inputLength = input.Length - inputOffset;
|
||||
if (inputLength == 0)
|
||||
{
|
||||
outputLength = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (input == null) throw new ArgumentNullException("input");
|
||||
if (inputOffset < 0 || inputOffset + inputLength > input.Length)
|
||||
throw new ArgumentException("inputOffset and inputLength are invalid for given input");
|
||||
|
||||
if (outputLength < 0) outputLength = output.Length - outputOffset;
|
||||
if (output == null) throw new ArgumentNullException("output");
|
||||
if (outputOffset < 0 || outputOffset + outputLength > output.Length)
|
||||
throw new ArgumentException("outputOffset and outputLength are invalid for given output");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content.Pipeline.Utilities
|
||||
{
|
||||
interface IVector4Converter<T> where T : struct
|
||||
{
|
||||
Vector4 ToVector4(T value);
|
||||
T FromVector4(Vector4 value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper class used by PixelBitmapContent.TryCopyFrom and TryCopyTo to convert between non-PackedValue types and Vector4.
|
||||
/// </summary>
|
||||
class Vector4Converter :
|
||||
IVector4Converter<byte>,
|
||||
IVector4Converter<short>,
|
||||
IVector4Converter<int>,
|
||||
IVector4Converter<float>,
|
||||
IVector4Converter<Color>,
|
||||
IVector4Converter<Vector4>
|
||||
{
|
||||
Vector4 IVector4Converter<byte>.ToVector4(byte value)
|
||||
{
|
||||
var f = (float)value / (float)byte.MaxValue;
|
||||
return new Vector4(f, 0f, 0f, 1f);
|
||||
}
|
||||
|
||||
Vector4 IVector4Converter<short>.ToVector4(short value)
|
||||
{
|
||||
var f = (float)value / (float)short.MaxValue;
|
||||
return new Vector4(f, 0f, 0f, 1f);
|
||||
}
|
||||
|
||||
Vector4 IVector4Converter<int>.ToVector4(int value)
|
||||
{
|
||||
var f = (float)value / (float)int.MaxValue;
|
||||
return new Vector4(f, 0f, 0f, 1f);
|
||||
}
|
||||
|
||||
Vector4 IVector4Converter<float>.ToVector4(float value)
|
||||
{
|
||||
return new Vector4(value, 0f, 0f, 1f);
|
||||
}
|
||||
|
||||
Vector4 IVector4Converter<Color>.ToVector4(Color value)
|
||||
{
|
||||
return value.ToVector4();
|
||||
}
|
||||
|
||||
Vector4 IVector4Converter<Vector4>.ToVector4(Vector4 value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
byte IVector4Converter<byte>.FromVector4(Vector4 value)
|
||||
{
|
||||
return (byte)(value.X * (float)byte.MaxValue);
|
||||
}
|
||||
|
||||
short IVector4Converter<short>.FromVector4(Vector4 value)
|
||||
{
|
||||
return (short)(value.X * (float)short.MaxValue);
|
||||
}
|
||||
|
||||
int IVector4Converter<int>.FromVector4(Vector4 value)
|
||||
{
|
||||
return (int)(value.X * (float)int.MaxValue);
|
||||
}
|
||||
|
||||
float IVector4Converter<float>.FromVector4(Vector4 value)
|
||||
{
|
||||
return value.X;
|
||||
}
|
||||
|
||||
Color IVector4Converter<Color>.FromVector4(Vector4 value)
|
||||
{
|
||||
return new Color(value);
|
||||
}
|
||||
|
||||
Vector4 IVector4Converter<Vector4>.FromVector4(Vector4 value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user