completely LZ4 support(0.8.1)
This commit is contained in:
Родитель
23674873e0
Коммит
bf5f2dd91b
|
@ -16,6 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{344DC89D-8
|
|||
.gitignore = .gitignore
|
||||
make_unity_symlink.bat = make_unity_symlink.bat
|
||||
nuget\MessagePack.ImmutableCollection.nuspec = nuget\MessagePack.ImmutableCollection.nuspec
|
||||
nuget\MessagePack.LZ4.nuspec = nuget\MessagePack.LZ4.nuspec
|
||||
nuget\MessagePack.nuspec = nuget\MessagePack.nuspec
|
||||
nuget\MessagePack.ReactiveProperty.nuspec = nuget\MessagePack.ReactiveProperty.nuspec
|
||||
nuget\MessagePack.UnityShims.nuspec = nuget\MessagePack.UnityShims.nuspec
|
||||
|
|
|
@ -3,7 +3,7 @@ MessagePack for C#(.NET, .NET Core, Unity, Xamarin)
|
|||
|
||||
> TODO:Writing document now.
|
||||
|
||||
Extremely fast [MessagePack](http://msgpack.org/) serializer for C#, x10~20 faster than MsgPack-Cli and acquires best performance compared with all the other C# serializers. Performance is always important! for Game, Distributed Computing, MicroServices, Store Data to Redis, etc.
|
||||
Extremely fast [MessagePack](http://msgpack.org/) serializer for C#, x10~20 faster than MsgPack-Cli and acquires best performance compared with all the other C# serializers. Built-in LZ4 compression extension can achieve super fast and small binary size. Performance is always important! for Game, Distributed Computing, MicroServices, Store Data to Redis, etc.
|
||||
|
||||
![image](https://cloud.githubusercontent.com/assets/46207/23487810/e263277a-ff2b-11e6-81a6-6b4ca7acd8e3.png)
|
||||
|
||||
|
@ -30,6 +30,7 @@ Install-Package MessagePackAnalyzer
|
|||
Extension Packages(info is see extension section).
|
||||
|
||||
```
|
||||
Install-Package MessagePack.LZ4
|
||||
Install-Package MessagePack.ImmutableCollection
|
||||
Install-Package MessagePack.ReactiveProperty
|
||||
Install-Package MessagePack.UnityShims
|
||||
|
@ -131,6 +132,8 @@ Performance
|
|||
TODO:
|
||||
|
||||
|
||||
// LZ4 result
|
||||
|
||||
|
||||
Extensions
|
||||
---
|
||||
|
|
|
@ -18,3 +18,7 @@ mklink ".\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\Unity\Formatter
|
|||
mklink ".\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\UnsafeExtensions\UnityBlitResolver.cs" "..\..\..\..\..\MessagePack.UnityShims\Extension\UnityBlitResolver.cs"
|
||||
mklink ".\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\UnsafeExtensions\UnsafeBlitFormatter.cs" "..\..\..\..\..\MessagePack.UnityShims\Extension\UnsafeBlitFormatter.cs"
|
||||
mklink ".\src\MessagePack.UnityClient\Assets\Scripts\Tests\Class1.cs" "..\..\..\..\..\sandbox\SharedData\Class1.cs"
|
||||
mklink /D ".\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\LZ4\Codec" "..\..\..\..\..\MessagePack.LZ4\LZ4\Codec"
|
||||
mklink ".\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\LZ4\LZ4MessagePackSerializer.cs" "..\..\..\..\..\MessagePack.LZ4\LZ4MessagePackSerializer.cs"
|
||||
mklink ".\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\LZ4\LZ4MessagePackSerializer.JSON.cs" "..\..\..\..\..\MessagePack.LZ4\LZ4MessagePackSerializer.JSON.cs"
|
||||
mklink ".\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\LZ4\LZ4MessagePackSerializer.NonGeneric.cs" "..\..\..\..\..\MessagePack.LZ4\LZ4MessagePackSerializer.NonGeneric.cs"
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MessagePack.ImmutableCollection</id>
|
||||
<version>0.7.2</version>
|
||||
<version>0.8.1</version>
|
||||
<title>MessagePack for C# Extension Support for ImmutableCollection</title>
|
||||
<authors>neuecc</authors>
|
||||
<owners>neuecc</owners>
|
||||
|
@ -17,11 +17,11 @@
|
|||
</frameworkAssemblies>
|
||||
<dependencies>
|
||||
<group targetFramework=".NETFramework4.5">
|
||||
<dependency id="MessagePack" version="0.7.2" />
|
||||
<dependency id="MessagePack" version="0.8.1" />
|
||||
<dependency id="System.Collections.Immutable" version="1.3.1" />
|
||||
</group>
|
||||
<group targetFramework=".NETStandard1.4">
|
||||
<dependency id="MessagePack" version="0.7.2" />
|
||||
<dependency id="MessagePack" version="0.8.1" />
|
||||
<dependency id="System.Collections.Immutable" version="1.3.1" />
|
||||
</group>
|
||||
</dependencies>
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MessagePack.LZ4</id>
|
||||
<version>0.8.1</version>
|
||||
<title>MessagePack for C#, LZ4 Compression Support</title>
|
||||
<authors>neuecc</authors>
|
||||
<owners>neuecc</owners>
|
||||
<projectUrl>https://github.com/neuecc/MessagePack-CSharp/</projectUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>Extremely Fast MessagePack Serializer for C#(.NET, .NET Core, Unity), LZ4 Compression Support.</description>
|
||||
<releaseNotes>Initial LZ4 Extension.</releaseNotes>
|
||||
<tags>MsgPack, MessagePack, Serialization, Formatter, Serializer, LZ4, Compression</tags>
|
||||
<frameworkAssemblies>
|
||||
<frameworkAssembly assemblyName="System" targetFramework=".NETFramework4.5" />
|
||||
<frameworkAssembly assemblyName="System.Core" targetFramework=".NETFramework4.5" />
|
||||
</frameworkAssemblies>
|
||||
<dependencies>
|
||||
<group targetFramework=".NETFramework4.5">
|
||||
<dependency id="MessagePack" version="0.8.1" />
|
||||
</group>
|
||||
<group targetFramework=".NETStandard1.4">
|
||||
<dependency id="MessagePack" version="0.8.1" />
|
||||
</group>
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\src\MessagePack.LZ4\bin\Release\netstandard1.4\MessagePack.LZ4.dll" target="lib\net45" />
|
||||
<file src="..\src\MessagePack.LZ4\bin\Release\netstandard1.4\MessagePack.LZ4.xml" target="lib\net45" />
|
||||
<file src="..\src\MessagePack.LZ4\bin\Release\netstandard1.4\MessagePack.LZ4.dll" target="lib\netstandard1.4" />
|
||||
<file src="..\src\MessagePack.LZ4\bin\Release\netstandard1.4\MessagePack.LZ4.xml" target="lib\netstandard1.4" />
|
||||
</files>
|
||||
</package>
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MessagePack.ReactiveProperty</id>
|
||||
<version>0.7.2</version>
|
||||
<version>0.8.1</version>
|
||||
<title>MessagePack for C# Extension Support for ReactiveProperty</title>
|
||||
<authors>neuecc</authors>
|
||||
<owners>neuecc</owners>
|
||||
|
@ -17,11 +17,11 @@
|
|||
</frameworkAssemblies>
|
||||
<dependencies>
|
||||
<group targetFramework=".NETFramework4.5">
|
||||
<dependency id="MessagePack" version="0.7.2" />
|
||||
<dependency id="MessagePack" version="0.8.1" />
|
||||
<dependency id="ReactiveProperty" version="3.5.1" />
|
||||
</group>
|
||||
<group targetFramework=".NETStandard1.4">
|
||||
<dependency id="MessagePack" version="0.7.2" />
|
||||
<dependency id="MessagePack" version="0.8.1" />
|
||||
<dependency id="ReactiveProperty" version="3.5.1" />
|
||||
</group>
|
||||
</dependencies>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MessagePack.UnityShims</id>
|
||||
<version>0.7.2</version>
|
||||
<version>0.8.1</version>
|
||||
<title>MessagePack for C# Extension Support for Unity(add pseudo Vector type and fast Vectory[] extension formatter)</title>
|
||||
<authors>neuecc</authors>
|
||||
<owners>neuecc</owners>
|
||||
|
@ -17,10 +17,10 @@
|
|||
</frameworkAssemblies>
|
||||
<dependencies>
|
||||
<group targetFramework=".NETFramework4.5">
|
||||
<dependency id="MessagePack" version="0.7.2" />
|
||||
<dependency id="MessagePack" version="0.8.1" />
|
||||
</group>
|
||||
<group targetFramework=".NETStandard1.4">
|
||||
<dependency id="MessagePack" version="0.7.2" />
|
||||
<dependency id="MessagePack" version="0.8.1" />
|
||||
</group>
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
|
|
@ -2,14 +2,14 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MessagePack</id>
|
||||
<version>0.7.2</version>
|
||||
<version>0.8.1</version>
|
||||
<title>MessagePack for C#</title>
|
||||
<authors>neuecc</authors>
|
||||
<owners>neuecc</owners>
|
||||
<projectUrl>https://github.com/neuecc/MessagePack-CSharp/</projectUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>Extremely Fast MessagePack Serializer for C#(.NET, .NET Core, Unity).</description>
|
||||
<releaseNotes>improve code generator.</releaseNotes>
|
||||
<releaseNotes>for supports LZ4.</releaseNotes>
|
||||
<tags>MsgPack, MessagePack, Serialization, Formatter, Serializer</tags>
|
||||
<frameworkAssemblies>
|
||||
<frameworkAssembly assemblyName="System" targetFramework=".NETFramework4.5" />
|
||||
|
|
|
@ -2,4 +2,5 @@ nuget pack MessagePack.nuspec
|
|||
nuget pack MessagePack.ImmutableCollection.nuspec
|
||||
nuget pack MessagePack.ReactiveProperty.nuspec
|
||||
nuget pack MessagePack.UnityShims.nuspec
|
||||
nuget pack MessagePack.LZ4.nuspec
|
||||
nuget pack MessagePackAnalyzer.nuspec
|
|
@ -1,5 +1,6 @@
|
|||
nuget push MessagePack.0.7.2.nupkg -Source https://www.nuget.org/api/v2/package
|
||||
nuget push MessagePack.ImmutableCollection.0.7.2.nupkg -Source https://www.nuget.org/api/v2/package
|
||||
nuget push MessagePack.ReactiveProperty.0.7.2.nupkg -Source https://www.nuget.org/api/v2/package
|
||||
nuget push MessagePack.UnityShims.0.7.2.nupkg -Source https://www.nuget.org/api/v2/package
|
||||
nuget push MessagePack.0.8.1.nupkg -Source https://www.nuget.org/api/v2/package
|
||||
nuget push MessagePack.ImmutableCollection.0.8.1.nupkg -Source https://www.nuget.org/api/v2/package
|
||||
nuget push MessagePack.ReactiveProperty.0.8.1.nupkg -Source https://www.nuget.org/api/v2/package
|
||||
nuget push MessagePack.UnityShims.0.8.1.nupkg -Source https://www.nuget.org/api/v2/package
|
||||
nuget push MessagePack.LZ4.0.8.1.nupkg -Source https://www.nuget.org/api/v2/package
|
||||
REM nuget push MessagePackAnalyzer.1.3.0.nupkg -Source https://www.nuget.org/api/v2/package
|
|
@ -120,11 +120,8 @@ namespace Sandbox
|
|||
Benchmark(p);
|
||||
Console.WriteLine();
|
||||
Benchmark(l);
|
||||
|
||||
//var json = MessagePackSerializer.ToJson(MessagePackSerializer.NonGeneric.Serialize(typeof(Person), p));
|
||||
//Console.WriteLine(json);
|
||||
}
|
||||
|
||||
|
||||
static void Benchmark<T>(T target)
|
||||
{
|
||||
const int Iteration = 10000; // 10000
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
#if ENABLE_UNSAFE_RESOLVER
|
||||
|
||||
using System;
|
||||
|
||||
namespace LZ4
|
||||
{
|
||||
internal static partial class LZ4Codec
|
||||
{
|
||||
public static int Encode(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength)
|
||||
{
|
||||
if (IntPtr.Size == 4)
|
||||
{
|
||||
return LZ4Codec.Encode32(input, inputOffset, inputLength, output, outputOffset, outputLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
return LZ4Codec.Encode64(input, inputOffset, inputLength, output, outputOffset, outputLength);
|
||||
}
|
||||
}
|
||||
|
||||
public static int Decode(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength, bool knownOutputLength)
|
||||
{
|
||||
if (IntPtr.Size == 4)
|
||||
{
|
||||
return LZ4Codec.Decode32(input, inputOffset, inputLength, output, outputOffset, outputLength, knownOutputLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
return LZ4Codec.Decode64(input, inputOffset, inputLength, output, outputOffset, outputLength, knownOutputLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal unsafe static class Pool
|
||||
{
|
||||
[ThreadStatic]
|
||||
static ushort[] ushortPool;
|
||||
|
||||
[ThreadStatic]
|
||||
static uint[] uintPool;
|
||||
|
||||
[ThreadStatic]
|
||||
static byte*[] bytePool;
|
||||
|
||||
public static ushort[] GetUShortHashTablePool()
|
||||
{
|
||||
if (ushortPool == null)
|
||||
{
|
||||
ushortPool = new ushort[HASH64K_TABLESIZE];
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Clear(ushortPool, 0, ushortPool.Length);
|
||||
}
|
||||
return ushortPool;
|
||||
}
|
||||
|
||||
public static uint[] GetUIntHashTablePool()
|
||||
{
|
||||
if (uintPool == null)
|
||||
{
|
||||
uintPool = new uint[HASH_TABLESIZE];
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Clear(uintPool, 0, uintPool.Length);
|
||||
}
|
||||
return uintPool;
|
||||
}
|
||||
|
||||
public static byte*[] GetByteHashTablePool()
|
||||
{
|
||||
if (bytePool == null)
|
||||
{
|
||||
bytePool = new byte*[HASH_TABLESIZE];
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Clear(bytePool, 0, bytePool.Length);
|
||||
}
|
||||
return bytePool;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,397 @@
|
|||
#if ENABLE_UNSAFE_RESOLVER
|
||||
|
||||
#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 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--; */
|
||||
}
|
||||
}
|
||||
|
||||
#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 = Pool.GetUShortHashTablePool();
|
||||
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
|
||||
{
|
||||
throw new InvalidOperationException("MessagePack.LZ4 impl only supports 'true'.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 = Pool.GetUShortHashTablePool();
|
||||
fixed (ushort* h = &hashTable[0])
|
||||
{
|
||||
return LZ4_compress64kCtx_64(h, input, output, inputLength, outputLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var hashTable = Pool.GetUIntHashTablePool();
|
||||
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
|
||||
{
|
||||
throw new InvalidOperationException("MessagePack.LZ4 impl only supports 'true'.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <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);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,672 @@
|
|||
#if ENABLE_UNSAFE_RESOLVER
|
||||
|
||||
#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 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
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper restore JoinDeclarationAndInitializer
|
||||
// ReSharper restore TooWideLocalVariableScope
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
#endif
|
|
@ -0,0 +1,673 @@
|
|||
#if ENABLE_UNSAFE_RESOLVER
|
||||
|
||||
#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 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
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper restore JoinDeclarationAndInitializer
|
||||
// ReSharper restore TooWideLocalVariableScope
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
#endif
|
|
@ -0,0 +1,162 @@
|
|||
#if ENABLE_UNSAFE_RESOLVER
|
||||
|
||||
#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;
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace 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;
|
||||
|
||||
#endregion
|
||||
|
||||
#region consts
|
||||
|
||||
private const int MINMATCH = 4;
|
||||
|
||||
#pragma warning disable 162, 429
|
||||
// ReSharper disable once UnreachableCode
|
||||
private const int SKIPSTRENGTH =
|
||||
NOTCOMPRESSIBLE_DETECTIONLEVEL > 2
|
||||
? NOTCOMPRESSIBLE_DETECTIONLEVEL
|
||||
: 2;
|
||||
#pragma warning restore 162, 429
|
||||
|
||||
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 = { 0, 3, 2, 3, 0, 0, 0, 0 };
|
||||
private static readonly int[] DECODER_TABLE_64 = { 0, 0, 0, -1, 0, 1, 2, 3 };
|
||||
|
||||
private static readonly int[] DEBRUIJN_TABLE_32 = {
|
||||
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 = {
|
||||
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
|
||||
|
||||
#endif
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
#if ENABLE_UNSAFE_RESOLVER
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
|
@ -37,7 +39,7 @@ namespace MessagePack
|
|||
if (header.TypeCode == ExtensionTypeCode)
|
||||
{
|
||||
// decode lz4
|
||||
var offset = checked((int)header.Length);
|
||||
var offset = readSize;
|
||||
var length = MessagePackBinary.ReadInt32(bytes, offset, out readSize);
|
||||
offset += readSize;
|
||||
|
||||
|
@ -227,3 +229,5 @@ namespace MessagePack
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,4 +1,7 @@
|
|||
using System;
|
||||
#if ENABLE_UNSAFE_RESOLVER
|
||||
#if NETSTANDARD1_4
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
|
@ -208,3 +211,6 @@ namespace MessagePack
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,61 +1,25 @@
|
|||
using System;
|
||||
#if ENABLE_UNSAFE_RESOLVER
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace MessagePack
|
||||
{
|
||||
/// <summary>
|
||||
/// LZ4 Compressed special serializer.
|
||||
/// LZ4 Compressed special serializer. Same API as MessagePackSerialzier but DefaultResolver is used MessagePackSerializer.DefaultResolver.
|
||||
/// </summary>
|
||||
public static partial class LZ4MessagePackSerializer
|
||||
{
|
||||
public const byte ExtensionTypeCode = 99;
|
||||
public const sbyte ExtensionTypeCode = 99;
|
||||
|
||||
public const int MinSize = 50;
|
||||
|
||||
static IFormatterResolver defaultResolver;
|
||||
|
||||
/// <summary>
|
||||
/// FormatterResolver that used resolver less overloads. If does not set it, used StandardResolver.
|
||||
/// </summary>
|
||||
public static IFormatterResolver DefaultResolver
|
||||
{
|
||||
get
|
||||
{
|
||||
if (defaultResolver == null)
|
||||
{
|
||||
defaultResolver = MessagePack.Resolvers.StandardResolver.Instance;
|
||||
}
|
||||
|
||||
return defaultResolver;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is resolver decided?
|
||||
/// </summary>
|
||||
public static bool IsInitialized
|
||||
{
|
||||
get
|
||||
{
|
||||
return defaultResolver != null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set default resolver of MessagePackSerializer APIs.
|
||||
/// </summary>
|
||||
/// <param name="resolver"></param>
|
||||
public static void SetDefaultResolver(IFormatterResolver resolver)
|
||||
{
|
||||
defaultResolver = resolver;
|
||||
}
|
||||
public const int NotCompressionSize = 64;
|
||||
|
||||
/// <summary>
|
||||
/// Serialize to binary with default resolver.
|
||||
/// </summary>
|
||||
public static byte[] Serialize<T>(T obj)
|
||||
{
|
||||
return Serialize(obj, defaultResolver);
|
||||
return Serialize(obj, MessagePackSerializer.DefaultResolver);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -63,7 +27,7 @@ namespace MessagePack
|
|||
/// </summary>
|
||||
public static byte[] Serialize<T>(T obj, IFormatterResolver resolver)
|
||||
{
|
||||
if (resolver == null) resolver = DefaultResolver;
|
||||
if (resolver == null) resolver = MessagePackSerializer.DefaultResolver;
|
||||
var buffer = SerializeCore(obj, resolver);
|
||||
|
||||
return MessagePackBinary.FastCloneWithResize(buffer.Array, buffer.Count);
|
||||
|
@ -74,7 +38,7 @@ namespace MessagePack
|
|||
/// </summary>
|
||||
public static void Serialize<T>(Stream stream, T obj)
|
||||
{
|
||||
Serialize(stream, obj, defaultResolver);
|
||||
Serialize(stream, obj, MessagePackSerializer.DefaultResolver);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -82,7 +46,7 @@ namespace MessagePack
|
|||
/// </summary>
|
||||
public static void Serialize<T>(Stream stream, T obj, IFormatterResolver resolver)
|
||||
{
|
||||
if (resolver == null) resolver = DefaultResolver;
|
||||
if (resolver == null) resolver = MessagePackSerializer.DefaultResolver;
|
||||
var buffer = SerializeCore(obj, resolver);
|
||||
|
||||
stream.Write(buffer.Array, 0, buffer.Count);
|
||||
|
@ -90,11 +54,9 @@ namespace MessagePack
|
|||
|
||||
static ArraySegment<byte> SerializeCore<T>(T obj, IFormatterResolver resolver)
|
||||
{
|
||||
var formatter = resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
var serializedData = MessagePackSerializer.SerializeUnsafe(obj, resolver);
|
||||
|
||||
if (serializedData.Count < MinSize)
|
||||
if (serializedData.Count < NotCompressionSize)
|
||||
{
|
||||
return serializedData;
|
||||
}
|
||||
|
@ -115,7 +77,7 @@ namespace MessagePack
|
|||
offset += MessagePackBinary.WriteInt32ForceInt32Block(ref buffer, offset, serializedData.Count);
|
||||
|
||||
// write body
|
||||
var lz4Length = global::LZ4.LZ4Codec.Encode(serializedData.Array, serializedData.Offset, serializedData.Count, buffer, offset, serializedData.Count);
|
||||
var lz4Length = global::LZ4.LZ4Codec.Encode(serializedData.Array, serializedData.Offset, serializedData.Count, buffer, offset, buffer.Length - offset);
|
||||
|
||||
return new ArraySegment<byte>(buffer, 0, lz4Length + offset);
|
||||
}
|
||||
|
@ -123,56 +85,63 @@ namespace MessagePack
|
|||
|
||||
public static T Deserialize<T>(byte[] bytes)
|
||||
{
|
||||
return Deserialize<T>(bytes, defaultResolver);
|
||||
return Deserialize<T>(bytes, MessagePackSerializer.DefaultResolver);
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(byte[] bytes, IFormatterResolver resolver)
|
||||
{
|
||||
if (resolver == null) resolver = DefaultResolver;
|
||||
if (resolver == null) resolver = MessagePackSerializer.DefaultResolver;
|
||||
|
||||
return DeserializeCore<T>(new ArraySegment<byte>(bytes, 0, bytes.Length), resolver);
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(Stream stream)
|
||||
{
|
||||
return Deserialize<T>(stream, MessagePackSerializer.DefaultResolver);
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(Stream stream, IFormatterResolver resolver)
|
||||
{
|
||||
if (resolver == null) resolver = MessagePackSerializer.DefaultResolver;
|
||||
|
||||
var buffer = InternalMemoryPool.GetBuffer();
|
||||
|
||||
var len = FillFromStream(stream, ref buffer);
|
||||
|
||||
// note, current lz4impl needs to fit input byte[]...
|
||||
var newBytes = MessagePackBinary.FastCloneWithResize(buffer, len);
|
||||
return DeserializeCore<T>(new ArraySegment<byte>(newBytes, 0, newBytes.Length), resolver);
|
||||
}
|
||||
|
||||
static T DeserializeCore<T>(ArraySegment<byte> bytes, IFormatterResolver resolver)
|
||||
{
|
||||
var formatter = resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
int readSize;
|
||||
if (MessagePackBinary.GetMessagePackType(bytes, 0) == MessagePackType.Extension)
|
||||
if (MessagePackBinary.GetMessagePackType(bytes.Array, 0) == MessagePackType.Extension)
|
||||
{
|
||||
var header = MessagePackBinary.ReadExtensionFormatHeader(bytes, 0, out readSize);
|
||||
var header = MessagePackBinary.ReadExtensionFormatHeader(bytes.Array, bytes.Offset, out readSize);
|
||||
if (header.TypeCode == ExtensionTypeCode)
|
||||
{
|
||||
// decode lz4
|
||||
var offset = readSize;
|
||||
var length = MessagePackBinary.ReadInt32(bytes, offset, out readSize);
|
||||
var offset = bytes.Offset + readSize;
|
||||
var length = MessagePackBinary.ReadInt32(bytes.Array, offset, out readSize);
|
||||
offset += readSize;
|
||||
|
||||
var buffer = InternalMemoryPool.GetBuffer();
|
||||
if (!(buffer.Length < length))
|
||||
if (buffer.Length < length)
|
||||
{
|
||||
buffer = new byte[length];
|
||||
}
|
||||
|
||||
// LZ4 Decode
|
||||
global::LZ4.LZ4Codec.Decode(bytes, offset, bytes.Length - offset, buffer, 0, length, true);
|
||||
global::LZ4.LZ4Codec.Decode(bytes.Array, offset, bytes.Count - offset, buffer, 0, length, true);
|
||||
|
||||
return formatter.Deserialize(buffer, 0, resolver, out readSize);
|
||||
}
|
||||
}
|
||||
|
||||
return formatter.Deserialize(bytes, 0, resolver, out readSize);
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(Stream stream)
|
||||
{
|
||||
return Deserialize<T>(stream, defaultResolver);
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(Stream stream, IFormatterResolver resolver)
|
||||
{
|
||||
if (resolver == null) resolver = DefaultResolver;
|
||||
var formatter = resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
var buffer = InternalMemoryPool.GetBuffer();
|
||||
|
||||
FillFromStream(stream, ref buffer);
|
||||
|
||||
return Deserialize<T>(buffer, resolver);
|
||||
return formatter.Deserialize(bytes.Array, bytes.Offset, resolver, out readSize);
|
||||
}
|
||||
|
||||
static int FillFromStream(Stream input, ref byte[] buffer)
|
||||
|
@ -207,3 +176,6 @@ namespace MessagePack
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -1,16 +1,22 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.6</TargetFramework>
|
||||
<TargetFramework>netstandard1.4</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DefineConstants>TRACE;RELEASE;NETSTANDARD1_6</DefineConstants>
|
||||
<DefineConstants>TRACE;RELEASE;NETSTANDARD1_4;ENABLE_UNSAFE_RESOLVER;</DefineConstants>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<OutputPath>bin\Release\netstandard1.4\</OutputPath>
|
||||
<DocumentationFile>bin\Release\netstandard1.4\MessagePack.LZ4.xml</DocumentationFile>
|
||||
<NoWarn>1701;1702;1705;1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="lz4net" Version="1.0.11.93" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<DefineConstants>TRACE;DEBUG;NETSTANDARD1_4;ENABLE_UNSAFE_RESOLVER;</DefineConstants>
|
||||
<OutputPath>bin\Debug\netstandard1.4\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MessagePack\MessagePack.csproj" />
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
../../../../../MessagePack.LZ4/LZ4/Codec
|
|
@ -0,0 +1 @@
|
|||
../../../../../MessagePack.LZ4/LZ4MessagePackSerializer.JSON.cs
|
|
@ -0,0 +1 @@
|
|||
../../../../../MessagePack.LZ4/LZ4MessagePackSerializer.NonGeneric.cs
|
|
@ -0,0 +1 @@
|
|||
../../../../../MessagePack.LZ4/LZ4MessagePackSerializer.cs
|
|
@ -100,6 +100,14 @@
|
|||
<Compile Include="Assets\Scripts\MessagePack\Internal\DynamicAssembly.cs" />
|
||||
<Compile Include="Assets\Scripts\MessagePack\Internal\ILGeneratorExtensions.cs" />
|
||||
<Compile Include="Assets\Scripts\MessagePack\Internal\ReflectionExtensions.cs" />
|
||||
<Compile Include="Assets\Scripts\MessagePack\LZ4\Codec\LZ4Codec.Helper.cs" />
|
||||
<Compile Include="Assets\Scripts\MessagePack\LZ4\Codec\LZ4Codec.Unsafe.cs" />
|
||||
<Compile Include="Assets\Scripts\MessagePack\LZ4\Codec\LZ4Codec.Unsafe32.Dirty.cs" />
|
||||
<Compile Include="Assets\Scripts\MessagePack\LZ4\Codec\LZ4Codec.Unsafe64.Dirty.cs" />
|
||||
<Compile Include="Assets\Scripts\MessagePack\LZ4\Codec\LZ4Codec.cs" />
|
||||
<Compile Include="Assets\Scripts\MessagePack\LZ4\LZ4MessagePackSerializer.JSON.cs" />
|
||||
<Compile Include="Assets\Scripts\MessagePack\LZ4\LZ4MessagePackSerializer.NonGeneric.cs" />
|
||||
<Compile Include="Assets\Scripts\MessagePack\LZ4\LZ4MessagePackSerializer.cs" />
|
||||
<Compile Include="Assets\Scripts\MessagePack\MessagePackBinary.cs" />
|
||||
<Compile Include="Assets\Scripts\MessagePack\MessagePackCode.cs" />
|
||||
<Compile Include="Assets\Scripts\MessagePack\MessagePackSerializer.Json.cs" />
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
using SharedData;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace MessagePack.Tests.ExtensionTests
|
||||
{
|
||||
|
||||
public class LZ4Test
|
||||
{
|
||||
T Convert<T>(T value)
|
||||
{
|
||||
var resolver = new WithImmutableDefaultResolver();
|
||||
return LZ4MessagePackSerializer.Deserialize<T>(LZ4MessagePackSerializer.Serialize(value, resolver), resolver);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void TestSmall()
|
||||
{
|
||||
// small size binary don't use LZ4 Encode
|
||||
MessagePackBinary.GetMessagePackType(LZ4MessagePackSerializer.Serialize(100), 0).Is(MessagePackType.Integer);
|
||||
MessagePackBinary.GetMessagePackType(LZ4MessagePackSerializer.Serialize("test"), 0).Is(MessagePackType.String);
|
||||
MessagePackBinary.GetMessagePackType(LZ4MessagePackSerializer.Serialize(false), 0).Is(MessagePackType.Boolean);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompressionData()
|
||||
{
|
||||
var originalData = Enumerable.Range(1, 1000).Select(x => x).ToArray();
|
||||
|
||||
var lz4Data = LZ4MessagePackSerializer.Serialize(originalData);
|
||||
|
||||
MessagePackBinary.GetMessagePackType(lz4Data, 0).Is(MessagePackType.Extension);
|
||||
int r;
|
||||
var header = MessagePackBinary.ReadExtensionFormatHeader(lz4Data, 0, out r);
|
||||
header.TypeCode.Is((sbyte)LZ4MessagePackSerializer.ExtensionTypeCode);
|
||||
|
||||
var decompress = LZ4MessagePackSerializer.Deserialize<int[]>(lz4Data);
|
||||
|
||||
decompress.Is(originalData);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NonGenericAPI()
|
||||
{
|
||||
var originalData = Enumerable.Range(1, 100).Select(x => new FirstSimpleData { Prop1 = x * x, Prop2 = "hoge", Prop3 = x }).ToArray();
|
||||
|
||||
var lz4Data = LZ4MessagePackSerializer.NonGeneric.Serialize(typeof(FirstSimpleData[]), originalData);
|
||||
|
||||
MessagePackBinary.GetMessagePackType(lz4Data, 0).Is(MessagePackType.Extension);
|
||||
int r;
|
||||
var header = MessagePackBinary.ReadExtensionFormatHeader(lz4Data, 0, out r);
|
||||
header.TypeCode.Is((sbyte)LZ4MessagePackSerializer.ExtensionTypeCode);
|
||||
|
||||
var decompress = LZ4MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), lz4Data);
|
||||
|
||||
decompress.IsStructuralEqual(originalData);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamAPI()
|
||||
{
|
||||
var originalData = Enumerable.Range(1, 100).Select(x => new FirstSimpleData { Prop1 = x * x, Prop2 = "hoge", Prop3 = x }).ToArray();
|
||||
|
||||
var ms = new MemoryStream();
|
||||
LZ4MessagePackSerializer.NonGeneric.Serialize(typeof(FirstSimpleData[]), ms, originalData);
|
||||
|
||||
var lz4normal = LZ4MessagePackSerializer.NonGeneric.Serialize(typeof(FirstSimpleData[]), originalData);
|
||||
|
||||
ms.Position = 0;
|
||||
|
||||
lz4normal.SequenceEqual(ms.ToArray()).IsTrue();
|
||||
|
||||
var decompress1 = LZ4MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), ms.ToArray());
|
||||
var decompress2 = LZ4MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), lz4normal);
|
||||
var decompress3 = LZ4MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), ms);
|
||||
|
||||
decompress1.IsStructuralEqual(originalData);
|
||||
decompress2.IsStructuralEqual(originalData);
|
||||
decompress3.IsStructuralEqual(originalData);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@
|
|||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
@ -102,6 +103,7 @@
|
|||
<Compile Include="CollectionTest.cs" />
|
||||
<Compile Include="DictionaryTest.cs" />
|
||||
<Compile Include="ExtensionTests\ImmutableCollectionTest.cs" />
|
||||
<Compile Include="ExtensionTests\LZ4Test.cs" />
|
||||
<Compile Include="ExtensionTests\ReactivePropertyTest.cs" />
|
||||
<Compile Include="ExtensionTests\UnityShimTest.cs" />
|
||||
<Compile Include="FormatterTest.cs" />
|
||||
|
@ -129,6 +131,10 @@
|
|||
<Project>{e066f547-7261-4561-aefc-e64dbfd874f8}</Project>
|
||||
<Name>MessagePack.ImmutableCollection</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\src\MessagePack.LZ4\MessagePack.LZ4.csproj">
|
||||
<Project>{6303cd14-f396-409c-bcbf-4da3105ec45c}</Project>
|
||||
<Name>MessagePack.LZ4</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\src\MessagePack.ReactiveProperty\MessagePack.ReactiveProperty.csproj">
|
||||
<Project>{166a16c0-b89f-41af-956a-235c6ca62c25}</Project>
|
||||
<Name>MessagePack.ReactiveProperty</Name>
|
||||
|
|
|
@ -41,5 +41,77 @@ namespace MessagePack.Tests
|
|||
new[] { data1.Prop2, data2.Prop2, data3.Prop2, data4.Prop2 }.Distinct().Is(data.Prop2);
|
||||
new[] { data1.Prop3, data2.Prop3, data3.Prop3, data4.Prop3 }.Distinct().Is(data.Prop3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamAPI()
|
||||
{
|
||||
var originalData = Enumerable.Range(1, 100).Select(x => new FirstSimpleData { Prop1 = x * x, Prop2 = "hoge", Prop3 = x }).ToArray();
|
||||
|
||||
var ms = new MemoryStream();
|
||||
MessagePackSerializer.NonGeneric.Serialize(typeof(FirstSimpleData[]), ms, originalData);
|
||||
|
||||
var normal = MessagePackSerializer.NonGeneric.Serialize(typeof(FirstSimpleData[]), originalData);
|
||||
|
||||
ms.Position = 0;
|
||||
|
||||
normal.SequenceEqual(ms.ToArray()).IsTrue();
|
||||
|
||||
var decompress1 = MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), ms.ToArray());
|
||||
var decompress2 = MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), normal);
|
||||
var decompress3 = MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), ms);
|
||||
ms.Position = 0;
|
||||
var onmore = new NonMemoryStream(ms);
|
||||
var decompress4 = MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), onmore);
|
||||
|
||||
decompress1.IsStructuralEqual(originalData);
|
||||
decompress2.IsStructuralEqual(originalData);
|
||||
decompress3.IsStructuralEqual(originalData);
|
||||
decompress4.IsStructuralEqual(originalData);
|
||||
}
|
||||
}
|
||||
|
||||
class NonMemoryStream : Stream
|
||||
{
|
||||
readonly MemoryStream stream;
|
||||
|
||||
public NonMemoryStream(MemoryStream stream)
|
||||
{
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
public override bool CanRead => stream.CanRead;
|
||||
|
||||
public override bool CanSeek => stream.CanSeek;
|
||||
|
||||
public override bool CanWrite => stream.CanWrite;
|
||||
|
||||
public override long Length => stream.Length;
|
||||
|
||||
public override long Position { get => stream.Position; set => stream.Position = value; }
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
stream.Flush();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return stream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return stream.Seek(offset, origin);
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
stream.SetLength(value);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
stream.Write(buffer, offset, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче