public void Complete()
        {
            if (_state == FseCompressorState.Completed)
            {
                return;
            }

            if (_state == FseCompressorState.NeedInput)
            {
                Compress();
            }

            _state = FseCompressorState.WriteOutput;
            Debug.Assert(_outputBuffer != null);

            uint checksum = _hash.GetFinalHash();

            checksum = (checksum >> 5) & ((1u << 22) - 1);

            Span <byte> block = _outputBuffer.AsSpan(_outputOffset + _bytesGenerated);

            block[2] = (byte)checksum;
            block[1] = (byte)(checksum >> 8);
            block[0] = (byte)((checksum >> 16) + (0b11 << 6));

            _bytesGenerated += 3;
            _headerWritten   = false;
            _hash            = XxHash32.Initialize();
        }
예제 #2
0
        public void Reset()
        {
            if (_compressor is null)
            {
                throw new ObjectDisposedException(nameof(FsePipeCompressor));
            }

            _compressor.Reset();
            _state = FseCompressorState.NeedInput;
        }
        public void Reset()
        {
            _state         = FseCompressorState.NeedInput;
            _headerWritten = false;
            _hash          = XxHash32.Initialize();

            _bytesRead      = 0;
            _outputOffset   = 0;
            _bytesGenerated = 0;
        }
예제 #4
0
        public void NotifyFlushCompleted()
        {
            if (_compressor is null)
            {
                throw new ObjectDisposedException(nameof(FsePipeCompressor));
            }

            if (_state == FseCompressorState.WriteOutput)
            {
                _state = _compressor.State;
                return;
            }

            throw new InvalidOperationException();
        }
예제 #5
0
        public void Complete()
        {
            if (_compressor is null)
            {
                throw new ObjectDisposedException(nameof(FsePipeCompressor));
            }

            _compressor.Complete();

            if (_compressor.State == FseCompressorState.WriteOutput)
            {
                ArraySegment <byte> output = _compressor.Output;
                _writer.Write(output.AsSpan());
                _compressor.Advance(output.Count);

                _state = FseCompressorState.WriteOutput;
            }
        }
        public void Advance(int count)
        {
            if (_state != FseCompressorState.WriteOutput)
            {
                throw new InvalidOperationException();
            }

            if ((uint)count > (uint)_bytesGenerated)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            _outputOffset   += count;
            _bytesGenerated -= count;
            if (_bytesGenerated == 0)
            {
                _bytesRead    = 0;
                _outputOffset = 0;
                _state        = _headerWritten ? FseCompressorState.NeedInput : FseCompressorState.Completed;
            }
        }
예제 #7
0
        public void Flush()
        {
            if (_compressor is null)
            {
                throw new ObjectDisposedException(nameof(FsePipeCompressor));
            }

            if (_state != FseCompressorState.NeedInput)
            {
                throw new InvalidOperationException();
            }

            _compressor.Flush();

            if (_compressor.State == FseCompressorState.WriteOutput)
            {
                ArraySegment <byte> output = _compressor.Output;
                _writer.Write(output.AsSpan());
                _compressor.Advance(output.Count);

                _state = FseCompressorState.WriteOutput;
            }
        }
예제 #8
0
        public void Process(ReadOnlySequence <byte> buffer, out SequencePosition consumed, out SequencePosition examined)
        {
            if (_compressor is null)
            {
                throw new ObjectDisposedException(nameof(FsePipeCompressor));
            }

            if (_state == FseCompressorState.WriteOutput)
            {
                throw new InvalidOperationException();
            }

            if (buffer.IsEmpty)
            {
                consumed = examined = default;
                return;
            }

            int consumedBytes = 0;

            foreach (ReadOnlyMemory <byte> segment in buffer)
            {
                consumedBytes += _compressor.SetInput(segment.Span);

                if (_compressor.State == FseCompressorState.WriteOutput)
                {
                    ArraySegment <byte> output = _compressor.Output;
                    _writer.Write(output.AsSpan());
                    _compressor.Advance(output.Count);

                    _state = FseCompressorState.WriteOutput;
                    break;
                }
            }

            consumed = examined = buffer.Slice(consumedBytes).Start;
        }
예제 #9
0
 public FsePipeCompressor(IBufferWriter <byte> writer)
 {
     _writer     = writer ?? throw new ArgumentNullException(nameof(writer));
     _compressor = new FseStreamCompressor();
     _state      = FseCompressorState.NeedInput;
 }
        private void Compress()
        {
            EnsureOutputBufferAllocated();

            Debug.Assert(_state == FseCompressorState.NeedInput);
            Debug.Assert(_bytesGenerated == 0);

            int         inSize       = _bytesRead;
            Span <byte> inputBuffer  = _inputBuffer.AsSpan(0, inSize);
            Span <byte> outputBuffer = _outputBuffer.AsSpan(0, _outputBufferBound);

            int headerSize;

            if (inSize == 0)
            {
                headerSize = 0;
            }
            else
            {
                _hash.Update(inputBuffer);
                int cSize = FseBlockCompressor.Compress(outputBuffer.Slice(10), inputBuffer);
                if (cSize == 0)
                {
                    // raw
                    if (inSize == _inputBufferSize)
                    {
                        outputBuffer[9] = (0b01 << 6) + 0x20;
                        headerSize      = 1;
                    }
                    else
                    {
                        outputBuffer[7] = (byte)(0b01 << 6);
                        outputBuffer[8] = (byte)(inSize >> 8);
                        outputBuffer[9] = (byte)inSize;
                        headerSize      = 3;
                    }
                    inputBuffer.CopyTo(outputBuffer.Slice(10));
                    _bytesGenerated = inSize;
                }
                else if (cSize == 1)
                {
                    // rle
                    if (inSize == _inputBufferSize)
                    {
                        outputBuffer[9] = (0b10 << 6) + 0x20;
                        headerSize      = 1;
                    }
                    else
                    {
                        outputBuffer[7] = (byte)(0b10 << 6);
                        outputBuffer[8] = (byte)(inSize >> 8);
                        outputBuffer[9] = (byte)inSize;
                        headerSize      = 3;
                    }
                    outputBuffer[10] = inputBuffer[0];
                    _bytesGenerated  = 1;
                }
                else
                {
                    // compressed
                    if (inSize == _inputBufferSize)
                    {
                        outputBuffer[7] = (0b00 << 6) + 0x20;
                        outputBuffer[8] = (byte)(cSize >> 8);
                        outputBuffer[9] = (byte)cSize;
                        headerSize      = 3;
                    }
                    else
                    {
                        outputBuffer[5] = 0b00 << 6;
                        outputBuffer[6] = (byte)(inSize >> 8);
                        outputBuffer[7] = (byte)inSize;
                        outputBuffer[8] = (byte)(cSize >> 8);
                        outputBuffer[9] = (byte)cSize;
                        headerSize      = 5;
                    }
                    _bytesGenerated = cSize;
                }
            }

            if (!_headerWritten)
            {
                BinaryPrimitives.WriteInt32LittleEndian(outputBuffer.Slice(5 - headerSize, 4), (int)FseCompressingAlgorithm.Fse);
                outputBuffer[9 - headerSize] = (byte)_blockSizeId;
                headerSize    += 5;
                _headerWritten = true;
            }

            _outputOffset    = 10 - headerSize;
            _bytesGenerated += headerSize;

            if (_bytesGenerated == 0)
            {
                _state = FseCompressorState.NeedInput;
            }
            else
            {
                _state = FseCompressorState.WriteOutput;
            }
        }