Beispiel #1
0
 public BrotliStream(Stream baseStream, CompressionMode mode, bool leaveOpen = false, int bufferSize = DefaultBufferSize)
 {
     if (baseStream == null)
     {
         throw new ArgumentNullException("baseStream");
     }
     _bufferSize = bufferSize;
     _mode       = mode;
     _stream     = baseStream;
     _leaveOpen  = leaveOpen;
     _state      = new Brotli.State();
     if (_mode == CompressionMode.Compress)
     {
         _state.SetQuality();
         _state.SetWindow();
         WriteTimeout = 0;
     }
     else
     {
         ReadTimeout = 0;
     }
     _buffer = new byte[_bufferSize];
     _transformationResult = TransformationStatus.NeedMoreSourceData;
     _availableOutput      = _bufferSize;
 }
Beispiel #2
0
        private void ValidateCompressedData(Span <byte> data, byte[] expected)
        {
            byte[] decompressed         = new byte[expected.Length];
            TransformationStatus result = Brotli.Decompress(data, decompressed, out int consumed, out int written);

            Assert.Equal <TransformationStatus>(TransformationStatus.Done, result);
            Assert.Equal <byte>(expected, decompressed);
        }
Beispiel #3
0
        private void ValidateCompressedData(byte[] data, byte[] expected)
        {
            byte[]               decompressed = new byte[expected.Length];
            Brotli.State         state        = new Brotli.State();
            TransformationStatus result       = Brotli.Decompress(data, decompressed, out int consumed, out int written, ref state);

            Assert.Equal <TransformationStatus>(TransformationStatus.Done, result);
            Assert.Equal <long>(expected.Length, written);
            Assert.Equal <long>(consumed, 0);
            Assert.Equal <byte>(expected, decompressed);
        }
Beispiel #4
0
        public void RoundtripCompressDecompress(int totalSize)
        {
            byte[] data = new byte[totalSize];
            new Random(42).NextBytes(data);
            Span <byte>          compressed = new byte[Brotli.GetMaximumCompressedSize(totalSize)];
            TransformationStatus result     = Brotli.Compress(data, compressed, out int consumed, out int written);

            Assert.Equal(TransformationStatus.Done, result);
            Assert.Equal(totalSize, consumed);
            compressed = compressed.Slice(0, written);
            ValidateCompressedData(compressed, data);
        }
        public void ToUpperInPlace(int from, int to, TransformationStatus expectedStatus, int expectedProcessed)
        {
            var buffer = Create(from, to);
            var copy   = new byte[buffer.Length];

            buffer.AsSpan().CopyTo(copy);

            var status = Ascii.ToUpperInPlace(buffer, out int processedBytes);

            Assert.Equal(expectedStatus, status);
            Assert.Equal(expectedProcessed, processedBytes);

            var clr         = Encoding.ASCII.GetString(copy, 0, processedBytes).ToUpperInvariant();
            var transformed = Encoding.ASCII.GetString(buffer, 0, processedBytes);
        }
Beispiel #6
0
        public void RoundtripCompressDecompress(int totalSize)
        {
            byte[] data = new byte[totalSize];
            new Random(42).NextBytes(data);
            byte[] compressed = new byte[Brotli.GetMaximumCompressedSize(totalSize)];
            Assert.NotEqual(compressed.Length, 0);
            Brotli.State         state  = new Brotli.State();
            TransformationStatus result = Brotli.Compress(data, compressed, out int consumed, out int written, ref state);

            while (consumed != 0 || result != TransformationStatus.Done)
            {
                result = Brotli.Compress(data, compressed, out consumed, out written, ref state);
            }
            byte[] flush = new byte[0];
            result = Brotli.FlushEncoder(flush, compressed, out consumed, out written, ref state);
            Assert.Equal(TransformationStatus.Done, result);
            Assert.Equal(consumed, 0);
            byte[] resultCompressed = new byte[written];
            Array.Copy(compressed, resultCompressed, written);
            ValidateCompressedData(resultCompressed, data);
        }
Beispiel #7
0
        public override void Write(byte[] buffer, int offset, int count)
        {
            EnsureCompressionMode();
            ValidateParameters(buffer, offset, count);
            EnsureNotDisposed();
            if (_mode != CompressionMode.Compress)
            {
                totalWrote += count;
            }
            DateTime begin         = DateTime.Now;
            int      bytesRemain   = count;
            int      currentOffset = offset;
            int      copyLen;

            while (bytesRemain > 0)
            {
                TimeSpan ExecutionTime = DateTime.Now - begin;
                if (WriteTimeout > 0 && ExecutionTime.TotalMilliseconds >= WriteTimeout)
                {
                    throw new TimeoutException(BrotliEx.TimeoutWrite);
                }
                copyLen = bytesRemain > _bufferSize ? _bufferSize : bytesRemain;
                Span <byte> bufferInput = new Span <byte>(buffer, currentOffset, copyLen);
                _transformationResult = TransformationStatus.DestinationTooSmall;
                _transformationResult = Brotli.Compress(bufferInput, _buffer, out _availableInput, out _availableOutput, ref _state);
                if (_transformationResult == TransformationStatus.InvalidData)
                {
                    throw new System.Exception(BrotliEx.unableEncode);
                }
                if (_transformationResult == TransformationStatus.DestinationTooSmall)
                {
                    _stream.Write(_buffer, 0, _availableOutput);
                }
                bytesRemain   -= copyLen;
                currentOffset += copyLen;
            }
        }
Beispiel #8
0
        public override int Read(byte[] buffer, int offset, int count)
        {
            EnsureDecompressionMode();
            ValidateParameters(buffer, offset, count);
            EnsureNotDisposed();
            DateTime begin = DateTime.Now;

            _availableOutput = 0;
            TimeSpan ExecutionTime = DateTime.Now - begin;

            if (ReadTimeout > 0 && ExecutionTime.TotalMilliseconds >= ReadTimeout)
            {
                throw new TimeoutException(BrotliEx.TimeoutRead);
            }
            while (true)
            {
                if (_transformationResult == TransformationStatus.NeedMoreSourceData)
                {
                    _availableInput = _stream.Read(_buffer, 0, _bufferSize);
                    if ((int)_availableInput <= 0)
                    {
                        break;
                    }
                }
                else if (_transformationResult != TransformationStatus.DestinationTooSmall)
                {
                    break;
                }
                _transformationResult = Brotli.Decompress(_buffer, buffer, out _availableInput, out _availableOutput, ref _state);
                if (_availableOutput != 0)
                {
                    return(_availableOutput);
                }
            }
            return(0);
        }
Beispiel #9
0
        protected virtual void FlushEncoder(bool finished)
        {
            if (_state.BrotliNativeState == IntPtr.Zero)
            {
                return;
            }
            if (BrotliNative.BrotliEncoderIsFinished(_state.BrotliNativeState))
            {
                return;
            }
            TransformationStatus flushStatus = TransformationStatus.DestinationTooSmall;

            while (flushStatus == TransformationStatus.DestinationTooSmall)
            {
                flushStatus = Brotli.FlushEncoder(Array.Empty <byte>(), _buffer, out _availableInput, out _availableOutput, ref _state, finished);
                _stream.Write(_buffer, 0, _availableOutput);
                _availableOutput = _bufferSize;

                if (BrotliNative.BrotliEncoderIsFinished(_state.BrotliNativeState))
                {
                    break;
                }
            }
        }
Beispiel #10
0
        public static void Pipe(this Transformation transformation, ReadOnlyBytes source, IOutput destination)
        {
            int afterMergeSlice = 0;
            ReadOnlySpan <byte> remainder;
            Span <byte>         stackSpan;

            unsafe
            {
                byte *stackBytes = stackalloc byte[stackLength];
                stackSpan = new Span <byte>(stackBytes, stackLength);
            }

            var poisition = Position.First;

            while (source.TryGet(ref poisition, out var sourceBuffer, true))
            {
                Span <byte>         outputSpan = destination.Buffer;
                ReadOnlySpan <byte> sourceSpan = sourceBuffer.Span;

                if (!remainder.IsEmpty)
                {
                    int leftOverBytes = remainder.Length;
                    remainder.CopyTo(stackSpan);
                    int amountToCopy = Math.Min(sourceSpan.Length, stackSpan.Length - leftOverBytes);
                    sourceSpan.Slice(0, amountToCopy).CopyTo(stackSpan.Slice(leftOverBytes));
                    int amountOfData = leftOverBytes + amountToCopy;

                    Span <byte> spanToTransform = stackSpan.Slice(0, amountOfData);

TryTransformWithRemainder:
                    TransformationStatus status = transformation.Transform(spanToTransform, outputSpan, out int bytesConsumed, out int bytesWritten);
                    if (status != TransformationStatus.Done)
                    {
                        destination.Advance(bytesWritten);
                        spanToTransform = spanToTransform.Slice(bytesConsumed);

                        if (status == TransformationStatus.DestinationTooSmall)
                        {
                            destination.Enlarge();  // output buffer is too small
                            outputSpan = destination.Buffer;

                            if (outputSpan.Length - bytesWritten < 3)
                            {
                                return; // no more output space, user decides what to do.
                            }
                            goto TryTransformWithRemainder;
                        }
                        else
                        {
                            if (status == TransformationStatus.InvalidData)
                            {
                                continue; // source buffer contains invalid bytes, user decides what to do for fallback
                            }

                            // at this point, status = TransformationStatus.NeedMoreSourceData
                            // left over bytes in stack span
                            remainder = spanToTransform;
                        }
                        continue;
                    }
                    else    // success
                    {
                        afterMergeSlice = bytesConsumed - remainder.Length;
                        remainder       = Span <byte> .Empty;
                        destination.Advance(bytesWritten);
                        outputSpan = destination.Buffer;
                    }
                }

TryTransform:
                TransformationStatus result = transformation.Transform(sourceSpan.Slice(afterMergeSlice), outputSpan, out int consumed, out int written);
                afterMergeSlice             = 0;
                destination.Advance(written);
                sourceSpan = sourceSpan.Slice(consumed);

                if (result == TransformationStatus.Done)
                {
                    continue;
                }

                // Not successful
                if (result == TransformationStatus.DestinationTooSmall)
                {
                    destination.Enlarge();  // output buffer is too small
                    outputSpan = destination.Buffer;
                    if (outputSpan.Length - written < 3)
                    {
                        return; // no more output space, user decides what to do.
                    }
                    goto TryTransform;
                }
                else
                {
                    if (result == TransformationStatus.InvalidData)
                    {
                        continue; // source buffer contains invalid bytes, user decides what to do for fallback
                    }

                    // at this point, result = TransformationStatus.NeedMoreSourceData
                    // left over bytes in source span
                    remainder = sourceSpan;
                }
            }
            return;
        }
Beispiel #11
0
        public void UTF16ToUTF8EncodingTestForReadOnlySpanOfChar(byte[] expectedBytes, char[] chars, TransformationStatus expectedReturnVal)
        {
            ReadOnlySpan <byte> utf16  = new ReadOnlySpan <char>(chars).NonPortableCast <char, byte>();
            Span <byte>         buffer = new byte[expectedBytes.Length];

            Assert.Equal(expectedReturnVal, Encoders.Utf16.ToUtf8(utf16, buffer, out int consumed, out int written));
            Assert.Equal(expectedBytes.Length, written);

            if (expectedBytes.Length > 0)
            {
                Assert.Equal(utf16.Length, consumed);
                Assert.True(buffer.Slice(0, written).SequenceEqual(expectedBytes));
            }
        }