public unsafe void Write(ReadOnlySpan <byte> span) #endif { if (_mode != Mode.Compress) { throw new NotSupportedException("Write() not supported on decompression"); } int inputSize = span.Length; while (0 < span.Length) { int srcWorkSize = _bufferSize < span.Length ? _bufferSize : span.Length; UIntPtr outSizeVal; fixed(byte *dest = _workBuf) fixed(byte *src = span) { outSizeVal = LZ4Init.Lib.FrameCompressUpdate(_cctx, dest, (UIntPtr)_destBufSize, src, (UIntPtr)srcWorkSize, null); } LZ4FrameException.CheckReturnValue(outSizeVal); Debug.Assert(outSizeVal.ToUInt64() < int.MaxValue, "BufferSize should be <2GB"); int outSize = (int)outSizeVal.ToUInt64(); BaseStream.Write(_workBuf, 0, outSize); TotalOut += outSize; span = span.Slice(srcWorkSize); } TotalIn += inputSize; }
protected override void Dispose(bool disposing) { if (disposing && !_disposed) { if (_cctx != IntPtr.Zero) { // Compress FinishWrite(); UIntPtr ret = LZ4Init.Lib.FreeFrameCompressContext(_cctx); LZ4FrameException.CheckReturnValue(ret); _cctx = IntPtr.Zero; } if (_dctx != IntPtr.Zero) { UIntPtr ret = LZ4Init.Lib.FreeFrameDecompressContext(_dctx); LZ4FrameException.CheckReturnValue(ret); _dctx = IntPtr.Zero; } if (BaseStream != null) { Flush(); if (!_leaveOpen) { BaseStream.Dispose(); } BaseStream = null; } _disposed = true; } }
/// <summary> /// Create decompressing LZ4FrameStream. /// </summary> public unsafe LZ4FrameStream(Stream baseStream, LZ4FrameDecompressOptions compOpts) { LZ4Init.Manager.EnsureLoaded(); BaseStream = baseStream ?? throw new ArgumentNullException(nameof(baseStream)); _mode = Mode.Decompress; _disposed = false; // Check and set compress options _leaveOpen = compOpts.LeaveOpen; _bufferSize = CheckBufferSize(compOpts.BufferSize); // Prepare dctx UIntPtr ret = LZ4Init.Lib.CreateFrameDecompressContext(ref _dctx, FrameVersion); LZ4FrameException.CheckReturnValue(ret); // Remove LZ4 frame header from the baseStream byte[] headerBuf = new byte[4]; int readHeaderSize = BaseStream.Read(headerBuf, 0, 4); TotalIn += 4; if (readHeaderSize != 4 || !headerBuf.SequenceEqual(FrameMagicNumber)) { throw new InvalidDataException("BaseStream is not a valid LZ4 Frame Format"); } // Prepare a work buffer _workBuf = new byte[_bufferSize]; }
private unsafe void FinishWrite() { Debug.Assert(_mode == Mode.Compress, "FinishWrite() cannot be called in decompression"); UIntPtr outSizeVal; fixed(byte *dest = _workBuf) { outSizeVal = LZ4Init.Lib.FrameCompressEnd(_cctx, dest, (UIntPtr)_destBufSize, null); } LZ4FrameException.CheckReturnValue(outSizeVal); Debug.Assert(outSizeVal.ToUInt64() < int.MaxValue, "BufferSize should be <2GB"); int outSize = (int)outSizeVal.ToUInt64(); BaseStream.Write(_workBuf, 0, outSize); TotalOut += outSize; }
public unsafe int Read(Span <byte> span) #endif { if (_mode != Mode.Decompress) { throw new NotSupportedException("Read() not supported on compression"); } // Reached end of stream if (_decompSrcIdx == DecompressComplete) { return(0); } int readSize = 0; int destSize = span.Length; int destLeftBytes = span.Length; if (_firstRead) { // Write FrameMagicNumber into LZ4F_decompress UIntPtr headerSizeVal = (UIntPtr)4; UIntPtr destSizeVal = (UIntPtr)destSize; UIntPtr ret; fixed(byte *header = FrameMagicNumber) fixed(byte *dest = span) { ret = LZ4Init.Lib.FrameDecompress(_dctx, dest, ref destSizeVal, header, ref headerSizeVal, null); } LZ4FrameException.CheckReturnValue(ret); Debug.Assert(headerSizeVal.ToUInt64() <= int.MaxValue); Debug.Assert(destSizeVal.ToUInt64() <= int.MaxValue); if (headerSizeVal.ToUInt32() != 4u) { throw new InvalidOperationException("Not enough dest buffer"); } int destWritten = (int)destSizeVal.ToUInt32(); span = span.Slice(destWritten); TotalOut += destWritten; _firstRead = false; } while (0 < destLeftBytes) { if (_decompSrcIdx == _decompSrcCount) { // Read from _baseStream _decompSrcIdx = 0; _decompSrcCount = BaseStream.Read(_workBuf, 0, _workBuf.Length); TotalIn += _decompSrcCount; // _baseStream reached its end if (_decompSrcCount == 0) { _decompSrcIdx = DecompressComplete; break; } } UIntPtr srcSizeVal = (UIntPtr)(_decompSrcCount - _decompSrcIdx); UIntPtr destSizeVal = (UIntPtr)(destLeftBytes); UIntPtr ret; fixed(byte *src = _workBuf.AsSpan(_decompSrcIdx)) fixed(byte *dest = span) { ret = LZ4Init.Lib.FrameDecompress(_dctx, dest, ref destSizeVal, src, ref srcSizeVal, null); } LZ4FrameException.CheckReturnValue(ret); // The number of bytes consumed from srcBuffer will be written into *srcSizePtr (necessarily <= original value). Debug.Assert(srcSizeVal.ToUInt64() <= int.MaxValue); int srcConsumed = (int)srcSizeVal.ToUInt32(); _decompSrcIdx += srcConsumed; Debug.Assert(_decompSrcIdx <= _decompSrcCount); // The number of bytes decompressed into dstBuffer will be written into *dstSizePtr (necessarily <= original value). Debug.Assert(destSizeVal.ToUInt64() <= int.MaxValue); int destWritten = (int)destSizeVal.ToUInt32(); span = span.Slice(destWritten); destLeftBytes -= destWritten; TotalOut += destWritten; readSize += destWritten; } return(readSize); }
private static readonly byte[] FrameMagicNumber = { 0x04, 0x22, 0x4D, 0x18 }; // 0x184D2204 (LE) #endregion #region Constructor /// <summary> /// Create compressing LZ4FrameStream. /// </summary> public unsafe LZ4FrameStream(Stream baseStream, LZ4FrameCompressOptions compOpts) { LZ4Init.Manager.EnsureLoaded(); BaseStream = baseStream ?? throw new ArgumentNullException(nameof(baseStream)); _mode = Mode.Compress; _disposed = false; // Check and set compress options _leaveOpen = compOpts.LeaveOpen; _bufferSize = CheckBufferSize(compOpts.BufferSize); // Prepare cctx UIntPtr ret = LZ4Init.Lib.CreateFrameCompressContext(ref _cctx, FrameVersion); LZ4FrameException.CheckReturnValue(ret); // Prepare FramePreferences FramePreferences prefs = new FramePreferences { FrameInfo = new FrameInfo { BlockSizeId = compOpts.BlockSizeId, BlockMode = compOpts.BlockMode, ContentChecksumFlag = compOpts.ContentChecksumFlag, FrameType = compOpts.FrameType, ContentSize = compOpts.ContentSize, DictId = 0, BlockChecksumFlag = compOpts.BlockChecksumFlag, }, CompressionLevel = compOpts.Level, AutoFlush = compOpts.AutoFlush ? 1u : 0u, FavorDecSpeed = compOpts.FavorDecSpeed ? 1u : 0u, }; // Query the minimum required size of compress buffer // _bufferSize is the source size, frameSize is the (required) dest size UIntPtr frameSizeVal = LZ4Init.Lib.FrameCompressBound((UIntPtr)_bufferSize, prefs); Debug.Assert(frameSizeVal.ToUInt64() <= int.MaxValue); uint frameSize = frameSizeVal.ToUInt32(); /* * if (_bufferSize < frameSize) * _destBufSize = frameSize; */ _destBufSize = (uint)_bufferSize; if (_bufferSize < frameSize) { _destBufSize = frameSize; } _workBuf = new byte[_destBufSize]; // Write the frame header into _workBuf UIntPtr headerSizeVal; fixed(byte *dest = _workBuf) { headerSizeVal = LZ4Init.Lib.FrameCompressBegin(_cctx, dest, (UIntPtr)_bufferSize, prefs); } LZ4FrameException.CheckReturnValue(headerSizeVal); Debug.Assert(headerSizeVal.ToUInt64() < int.MaxValue); int headerSize = (int)headerSizeVal.ToUInt32(); BaseStream.Write(_workBuf, 0, headerSize); TotalOut += headerSize; }