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; }
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); }
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); }
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); }
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); }
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; } }
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); }
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; } } }
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; }
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)); } }