Пример #1
0
        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;
        }
Пример #2
0
        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;
            }
        }
Пример #3
0
        /// <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];
        }
Пример #4
0
        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;
        }
Пример #5
0
        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);
        }
Пример #6
0
        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;
        }