mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
Internal Fixes, etc. (#20)
* Start removing mixed usages
* Check for directories before opening
* Fix writing
* Kinda fix rebuild
* One more try
* Better internal handling
* Slighty fix a couple more things
* Update RVWorld Compress code to db7d750bba
* Fix build
Co-authored-by: Matt Nadareski <mnadareski@mparticle.com>
This commit is contained in:
194
SabreTools.Library/External/Compress/SevenZip/Compress/ZSTD/ZstandardDictionary.cs
vendored
Normal file
194
SabreTools.Library/External/Compress/SevenZip/Compress/ZSTD/ZstandardDictionary.cs
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Interop = Zstandard.Net.ZstandardInterop;
|
||||
|
||||
namespace Zstandard.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// A Zstandard dictionary improves the compression ratio and speed on small data dramatically.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A Zstandard dictionary is calculated with a high number of small sample data.
|
||||
/// Please refer to the Zstandard documentation for more details.
|
||||
/// </remarks>
|
||||
/// <seealso cref="System.IDisposable" />
|
||||
public sealed class ZstandardDictionary : IDisposable
|
||||
{
|
||||
private byte[] dictionary;
|
||||
private IntPtr ddict;
|
||||
private Dictionary<int, IntPtr> cdicts = new Dictionary<int, IntPtr>();
|
||||
private object lockObject = new object();
|
||||
private bool isDisposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardDictionary"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dictionary">The dictionary raw data.</param>
|
||||
public ZstandardDictionary(byte[] dictionary)
|
||||
{
|
||||
this.dictionary = dictionary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardDictionary"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dictionaryPath">The dictionary path.</param>
|
||||
public ZstandardDictionary(string dictionaryPath)
|
||||
{
|
||||
this.dictionary = File.ReadAllBytes(dictionaryPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardDictionary"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dictionaryStream">The dictionary stream.</param>
|
||||
public ZstandardDictionary(Stream dictionaryStream)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
dictionaryStream.CopyTo(memoryStream);
|
||||
this.dictionary = memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="ZstandardDictionary"/> class.
|
||||
/// </summary>
|
||||
~ZstandardDictionary()
|
||||
{
|
||||
this.Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged resources.
|
||||
/// </summary>
|
||||
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
||||
private void Dispose(bool dispose)
|
||||
{
|
||||
if (this.isDisposed == false)
|
||||
{
|
||||
this.isDisposed = true;
|
||||
|
||||
if (this.ddict != IntPtr.Zero)
|
||||
{
|
||||
Interop.ZSTD_freeDDict(this.ddict);
|
||||
this.ddict = IntPtr.Zero;
|
||||
}
|
||||
|
||||
foreach (var kv in this.cdicts.ToList())
|
||||
{
|
||||
Interop.ZSTD_freeCDict(kv.Value);
|
||||
this.cdicts.Remove(kv.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the compression dictionary for the specified compression level.
|
||||
/// </summary>
|
||||
/// <param name="compressionLevel">The compression level.</param>
|
||||
/// <returns>
|
||||
/// The IntPtr to the compression dictionary.
|
||||
/// </returns>
|
||||
/// <exception cref="ObjectDisposedException">ZstandardDictionary</exception>
|
||||
internal IntPtr GetCompressionDictionary(int compressionLevel)
|
||||
{
|
||||
if (this.isDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(ZstandardDictionary));
|
||||
}
|
||||
|
||||
lock (this.lockObject)
|
||||
{
|
||||
if (this.cdicts.TryGetValue(compressionLevel, out var cdict) == false)
|
||||
{
|
||||
this.cdicts[compressionLevel] = cdict = this.CreateCompressionDictionary(compressionLevel);
|
||||
}
|
||||
|
||||
return cdict;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the decompression dictionary.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The IntPtr to the decompression dictionary.
|
||||
/// </returns>
|
||||
/// <exception cref="ObjectDisposedException">ZstandardDictionary</exception>
|
||||
internal IntPtr GetDecompressionDictionary()
|
||||
{
|
||||
if (this.isDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(ZstandardDictionary));
|
||||
}
|
||||
|
||||
lock (this.lockObject)
|
||||
{
|
||||
if (this.ddict == IntPtr.Zero)
|
||||
{
|
||||
this.ddict = this.CreateDecompressionDictionary();
|
||||
}
|
||||
|
||||
return this.ddict;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new compression dictionary.
|
||||
/// </summary>
|
||||
/// <param name="compressionLevel">The compression level.</param>
|
||||
/// <returns>
|
||||
/// The IntPtr to the compression dictionary.
|
||||
/// </returns>
|
||||
private IntPtr CreateCompressionDictionary(int compressionLevel)
|
||||
{
|
||||
var alloc = GCHandle.Alloc(this.dictionary, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
var dictBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(this.dictionary, 0);
|
||||
var dictSize = new UIntPtr((uint)this.dictionary.Length);
|
||||
return Interop.ZSTD_createCDict(dictBuffer, dictSize, compressionLevel);
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc.Free();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new decompression dictionary.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The IntPtr to the decompression dictionary.
|
||||
/// </returns>
|
||||
private IntPtr CreateDecompressionDictionary()
|
||||
{
|
||||
var alloc = GCHandle.Alloc(this.dictionary, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
var dictBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(this.dictionary, 0);
|
||||
var dictSize = new UIntPtr((uint)this.dictionary.Length);
|
||||
return Interop.ZSTD_createDDict(dictBuffer, dictSize);
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
143
SabreTools.Library/External/Compress/SevenZip/Compress/ZSTD/ZstandardInterop.cs
vendored
Normal file
143
SabreTools.Library/External/Compress/SevenZip/Compress/ZSTD/ZstandardInterop.cs
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Zstandard.Net
|
||||
{
|
||||
internal static class ZstandardInterop
|
||||
{
|
||||
static ZstandardInterop()
|
||||
{
|
||||
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||
{
|
||||
var root = Path.GetDirectoryName(typeof(ZstandardInterop).Assembly.Location);
|
||||
var path = Environment.Is64BitProcess ? "x64" : "x86";
|
||||
var file = Path.Combine(root, path, "libzstd.dll");
|
||||
LoadLibraryEx(file, IntPtr.Zero, LoadLibraryFlags.LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class Buffer
|
||||
{
|
||||
public IntPtr Data = IntPtr.Zero;
|
||||
public UIntPtr Size = UIntPtr.Zero;
|
||||
public UIntPtr Position = UIntPtr.Zero;
|
||||
}
|
||||
|
||||
public static void ThrowIfError(UIntPtr code)
|
||||
{
|
||||
if (ZSTD_isError(code))
|
||||
{
|
||||
var errorPtr = ZSTD_getErrorName(code);
|
||||
var errorMsg = Marshal.PtrToStringAnsi(errorPtr);
|
||||
throw new IOException(errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[Flags]
|
||||
private enum LoadLibraryFlags : uint
|
||||
{
|
||||
DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
|
||||
LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
|
||||
LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
|
||||
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
|
||||
LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
|
||||
LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200,
|
||||
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000,
|
||||
LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100,
|
||||
LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800,
|
||||
LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400,
|
||||
LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
|
||||
}
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern uint ZSTD_versionNumber();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int ZSTD_maxCLevel();
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr ZSTD_createCStream();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_initCStream(IntPtr zcs, int compressionLevel);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_freeCStream(IntPtr zcs);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_CStreamInSize();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_CStreamOutSize();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_compressStream(IntPtr zcs, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer, [MarshalAs(UnmanagedType.LPStruct)] Buffer inputBuffer);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr ZSTD_createCDict(IntPtr dictBuffer, UIntPtr dictSize, int compressionLevel);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_freeCDict(IntPtr cdict);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_initCStream_usingCDict(IntPtr zcs, IntPtr cdict);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr ZSTD_createDStream();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_initDStream(IntPtr zds);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_freeDStream(IntPtr zds);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_DStreamInSize();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_DStreamOutSize();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_decompressStream(IntPtr zds, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer, [MarshalAs(UnmanagedType.LPStruct)] Buffer inputBuffer);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr ZSTD_createDDict(IntPtr dictBuffer, UIntPtr dictSize);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_freeDDict(IntPtr ddict);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_initDStream_usingDDict(IntPtr zds, IntPtr ddict);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_flushStream(IntPtr zcs, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_endStream(IntPtr zcs, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern bool ZSTD_isError(UIntPtr code);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern IntPtr ZSTD_getErrorName(UIntPtr code);
|
||||
}
|
||||
}
|
||||
398
SabreTools.Library/External/Compress/SevenZip/Compress/ZSTD/ZstandardStream.cs
vendored
Normal file
398
SabreTools.Library/External/Compress/SevenZip/Compress/ZSTD/ZstandardStream.cs
vendored
Normal file
@@ -0,0 +1,398 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Runtime.InteropServices;
|
||||
using Interop = Zstandard.Net.ZstandardInterop;
|
||||
|
||||
namespace Zstandard.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods and properties for compressing and decompressing streams by using the Zstandard algorithm.
|
||||
/// </summary>
|
||||
public class ZstandardStream : Stream
|
||||
{
|
||||
private Stream stream;
|
||||
private CompressionMode mode;
|
||||
private Boolean leaveOpen;
|
||||
private Boolean isClosed = false;
|
||||
private Boolean isDisposed = false;
|
||||
private Boolean isInitialized = false;
|
||||
|
||||
private IntPtr zstream;
|
||||
private uint zstreamInputSize;
|
||||
private uint zstreamOutputSize;
|
||||
|
||||
private byte[] data;
|
||||
private bool dataDepleted = false;
|
||||
private bool dataSkipRead = false;
|
||||
private int dataPosition = 0;
|
||||
private int dataSize = 0;
|
||||
|
||||
private long position = 0;
|
||||
|
||||
private Interop.Buffer outputBuffer = new Interop.Buffer();
|
||||
private Interop.Buffer inputBuffer = new Interop.Buffer();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardStream"/> class by using the specified stream and compression mode, and optionally leaves the stream open.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to compress.</param>
|
||||
/// <param name="mode">One of the enumeration values that indicates whether to compress or decompress the stream.</param>
|
||||
/// <param name="leaveOpen">true to leave the stream open after disposing the <see cref="ZstandardStream"/> object; otherwise, false.</param>
|
||||
public ZstandardStream(Stream stream, CompressionMode mode, bool leaveOpen = false)
|
||||
{
|
||||
this.stream = stream ?? throw new ArgumentNullException(nameof(stream));
|
||||
this.mode = mode;
|
||||
this.leaveOpen = leaveOpen;
|
||||
position = 0;
|
||||
|
||||
if (mode == CompressionMode.Compress)
|
||||
{
|
||||
this.zstreamInputSize = Interop.ZSTD_CStreamInSize().ToUInt32();
|
||||
this.zstreamOutputSize = Interop.ZSTD_CStreamOutSize().ToUInt32();
|
||||
this.zstream = Interop.ZSTD_createCStream();
|
||||
this.data = new byte[(int)this.zstreamOutputSize];
|
||||
}
|
||||
|
||||
if (mode == CompressionMode.Decompress)
|
||||
{
|
||||
this.zstreamInputSize = Interop.ZSTD_DStreamInSize().ToUInt32();
|
||||
this.zstreamOutputSize = Interop.ZSTD_DStreamOutSize().ToUInt32();
|
||||
this.zstream = Interop.ZSTD_createDStream();
|
||||
this.data = new byte[(int)this.zstreamInputSize];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardStream"/> class by using the specified stream and compression level, and optionally leaves the stream open.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to compress.</param>
|
||||
/// <param name="compressionLevel">The compression level.</param>
|
||||
/// <param name="leaveOpen">true to leave the stream open after disposing the <see cref="ZstandardStream"/> object; otherwise, false.</param>
|
||||
public ZstandardStream(Stream stream, int compressionLevel, bool leaveOpen = false) : this(stream, CompressionMode.Compress, leaveOpen)
|
||||
{
|
||||
this.CompressionLevel = compressionLevel;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// The version of the native Zstd library.
|
||||
/// </summary>
|
||||
public static Version Version
|
||||
{
|
||||
get
|
||||
{
|
||||
var version = (int)Interop.ZSTD_versionNumber();
|
||||
return new Version((version / 10000) % 100, (version / 100) % 100, version % 100);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The maximum compression level supported by the native Zstd library.
|
||||
/// </summary>
|
||||
public static int MaxCompressionLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return Interop.ZSTD_maxCLevel();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the compression level to use, the default is 6.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To get the maximum compression level see <see cref="MaxCompressionLevel"/>.
|
||||
/// </remarks>
|
||||
public int CompressionLevel { get; set; } = 6;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the compression dictionary tp use, the default is null.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The compression dictionary.
|
||||
/// </value>
|
||||
public ZstandardDictionary CompressionDictionary { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the current stream supports reading.
|
||||
/// </summary>
|
||||
public override bool CanRead => this.stream.CanRead && this.mode == CompressionMode.Decompress;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the current stream supports writing.
|
||||
/// </summary>
|
||||
public override bool CanWrite => this.stream.CanWrite && this.mode == CompressionMode.Compress;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the current stream supports seeking.
|
||||
/// </summary>
|
||||
public override bool CanSeek => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length in bytes of the stream.
|
||||
/// </summary>
|
||||
public override long Length => throw new NotSupportedException();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position within the current stream.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get => position;
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (this.isDisposed == false)
|
||||
{
|
||||
if (!this.isClosed) ReleaseResources(flushStream: false);
|
||||
this.isDisposed = true;
|
||||
this.data = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
if (this.isClosed) return;
|
||||
|
||||
try
|
||||
{
|
||||
ReleaseResources(flushStream: true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.isClosed = true;
|
||||
base.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseResources(bool flushStream)
|
||||
{
|
||||
if (this.mode == CompressionMode.Compress)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (flushStream)
|
||||
{
|
||||
this.ProcessStream((zcs, buffer) => Interop.ThrowIfError(Interop.ZSTD_flushStream(zcs, buffer)));
|
||||
this.ProcessStream((zcs, buffer) => Interop.ThrowIfError(Interop.ZSTD_endStream(zcs, buffer)));
|
||||
this.stream.Flush();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Interop.ZSTD_freeCStream(this.zstream);
|
||||
if (!this.leaveOpen) this.stream.Close();
|
||||
}
|
||||
}
|
||||
else if (this.mode == CompressionMode.Decompress)
|
||||
{
|
||||
Interop.ZSTD_freeDStream(this.zstream);
|
||||
if (!this.leaveOpen) this.stream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
if (this.mode == CompressionMode.Compress)
|
||||
{
|
||||
this.ProcessStream((zcs, buffer) => Interop.ThrowIfError(Interop.ZSTD_flushStream(zcs, buffer)));
|
||||
this.stream.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (this.CanRead == false) throw new NotSupportedException();
|
||||
|
||||
// prevent the buffers from being moved around by the garbage collector
|
||||
var alloc1 = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||
var alloc2 = GCHandle.Alloc(this.data, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
var length = 0;
|
||||
|
||||
if (this.isInitialized == false)
|
||||
{
|
||||
this.isInitialized = true;
|
||||
|
||||
var result = this.CompressionDictionary == null
|
||||
? Interop.ZSTD_initDStream(this.zstream)
|
||||
: Interop.ZSTD_initDStream_usingDDict(this.zstream, this.CompressionDictionary.GetDecompressionDictionary());
|
||||
}
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
var inputSize = this.dataSize - this.dataPosition;
|
||||
|
||||
// read data from input stream
|
||||
if (inputSize <= 0 && !this.dataDepleted && !this.dataSkipRead)
|
||||
{
|
||||
this.dataSize = this.stream.Read(this.data, 0, (int)this.zstreamInputSize);
|
||||
this.dataDepleted = this.dataSize <= 0;
|
||||
this.dataPosition = 0;
|
||||
inputSize = this.dataDepleted ? 0 : this.dataSize;
|
||||
|
||||
// skip stream.Read until the internal buffer is depleted
|
||||
// avoids a Read timeout for applications that know the exact number of bytes in the stream
|
||||
this.dataSkipRead = true;
|
||||
}
|
||||
|
||||
// configure the inputBuffer
|
||||
this.inputBuffer.Data = inputSize <= 0 ? IntPtr.Zero : Marshal.UnsafeAddrOfPinnedArrayElement(this.data, this.dataPosition);
|
||||
this.inputBuffer.Size = inputSize <= 0 ? UIntPtr.Zero : new UIntPtr((uint)inputSize);
|
||||
this.inputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
// configure the outputBuffer
|
||||
this.outputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset);
|
||||
this.outputBuffer.Size = new UIntPtr((uint)count);
|
||||
this.outputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
// decompress inputBuffer to outputBuffer
|
||||
Interop.ThrowIfError(Interop.ZSTD_decompressStream(this.zstream, this.outputBuffer, this.inputBuffer));
|
||||
|
||||
// calculate progress in outputBuffer
|
||||
var outputBufferPosition = (int)this.outputBuffer.Position.ToUInt32();
|
||||
if (outputBufferPosition == 0)
|
||||
{
|
||||
// the internal buffer is depleted, we're either done
|
||||
if (this.dataDepleted) break;
|
||||
|
||||
// or we need more bytes
|
||||
this.dataSkipRead = false;
|
||||
}
|
||||
length += outputBufferPosition;
|
||||
offset += outputBufferPosition;
|
||||
count -= outputBufferPosition;
|
||||
|
||||
// calculate progress in inputBuffer
|
||||
var inputBufferPosition = (int)inputBuffer.Position.ToUInt32();
|
||||
this.dataPosition += inputBufferPosition;
|
||||
}
|
||||
|
||||
position += length;
|
||||
return length;
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc1.Free();
|
||||
alloc2.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (this.CanWrite == false) throw new NotSupportedException();
|
||||
|
||||
// prevent the buffers from being moved around by the garbage collector
|
||||
var alloc1 = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||
var alloc2 = GCHandle.Alloc(this.data, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
if (this.isInitialized == false)
|
||||
{
|
||||
this.isInitialized = true;
|
||||
|
||||
var result = this.CompressionDictionary == null
|
||||
? Interop.ZSTD_initCStream(this.zstream, this.CompressionLevel)
|
||||
: Interop.ZSTD_initCStream_usingCDict(this.zstream, this.CompressionDictionary.GetCompressionDictionary(this.CompressionLevel));
|
||||
|
||||
Interop.ThrowIfError(result);
|
||||
}
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
var inputSize = Math.Min((uint)count, this.zstreamInputSize);
|
||||
|
||||
// configure the outputBuffer
|
||||
this.outputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(this.data, 0);
|
||||
this.outputBuffer.Size = new UIntPtr(this.zstreamOutputSize);
|
||||
this.outputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
// configure the inputBuffer
|
||||
this.inputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset);
|
||||
this.inputBuffer.Size = new UIntPtr((uint)inputSize);
|
||||
this.inputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
// compress inputBuffer to outputBuffer
|
||||
Interop.ThrowIfError(Interop.ZSTD_compressStream(this.zstream, this.outputBuffer, this.inputBuffer));
|
||||
|
||||
// write data to output stream
|
||||
var outputBufferPosition = (int)this.outputBuffer.Position.ToUInt32();
|
||||
this.stream.Write(this.data, 0, outputBufferPosition);
|
||||
|
||||
// calculate progress in inputBuffer
|
||||
var inputBufferPosition = (int)this.inputBuffer.Position.ToUInt32();
|
||||
offset += inputBufferPosition;
|
||||
count -= inputBufferPosition;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc1.Free();
|
||||
alloc2.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
if (origin != SeekOrigin.Current)
|
||||
throw new NotImplementedException();
|
||||
|
||||
byte[] tmpBuff = new byte[1024];
|
||||
long sizeToGo = offset;
|
||||
while (sizeToGo > 0)
|
||||
{
|
||||
int sizenow = sizeToGo > 1024 ? 1024 : (int)sizeToGo;
|
||||
Read(tmpBuff, 0, sizenow);
|
||||
sizeToGo -= sizenow;
|
||||
}
|
||||
|
||||
position += offset;
|
||||
return offset;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
private void ProcessStream(Action<IntPtr, Interop.Buffer> outputAction)
|
||||
{
|
||||
var alloc = GCHandle.Alloc(this.data, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
this.outputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(this.data, 0);
|
||||
this.outputBuffer.Size = new UIntPtr(this.zstreamOutputSize);
|
||||
this.outputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
outputAction(this.zstream, this.outputBuffer);
|
||||
|
||||
var outputBufferPosition = (int)this.outputBuffer.Position.ToUInt32();
|
||||
this.stream.Write(this.data, 0, outputBufferPosition);
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user