// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
-using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
public override int Read(byte[] buffer, int offset, int count)
{
ValidateBufferArguments(buffer, offset, count);
+ return Read(new Span<byte>(buffer, offset, count));
+ }
+
+ public override int Read(Span<byte> buffer)
+ {
EnsureNotDisposed();
- int bytesRead;
- int currentOffset = offset;
- int remainingCount = count;
+ int initialLength = buffer.Length;
+ int bytesRead;
while (true)
{
- bytesRead = _inflater.Inflate(buffer, currentOffset, remainingCount);
- currentOffset += bytesRead;
- remainingCount -= bytesRead;
+ bytesRead = _inflater.Inflate(buffer);
+ buffer = buffer.Slice(bytesRead);
- if (remainingCount == 0)
+ if (buffer.Length == 0)
{
break;
}
_inflater.SetInput(_buffer, 0, bytes);
}
- return count - remainingCount;
+ return initialLength - buffer.Length;
+ }
+
+ public override int ReadByte()
+ {
+ byte b = default;
+ return Read(MemoryMarshal.CreateSpan(ref b, 1)) == 1 ? b : -1;
}
private void EnsureNotDisposed()
try
{
// Try to read decompressed data in output buffer
- int bytesRead = _inflater.Inflate(buffer);
+ int bytesRead = _inflater.Inflate(buffer.Span);
if (bytesRead != 0)
{
// If decompression output buffer is not empty, return immediately.
// Feed the data from base stream into decompression engine
_inflater.SetInput(_buffer, 0, bytesRead);
- bytesRead = _inflater.Inflate(buffer);
+ bytesRead = _inflater.Inflate(buffer.Span);
if (bytesRead == 0 && !_inflater.Finished())
{
public int AvailableOutput => _output.AvailableBytes;
- public int Inflate(Memory<byte> bytes)
+ public int Inflate(Span<byte> bytes)
{
// copy bytes from output to outputbytes if we have available bytes
// if buffer is not filled up. keep decoding until no input are available
return count;
}
- public int Inflate(byte[] bytes, int offset, int length) => Inflate(bytes.AsMemory(offset, length));
+ public int Inflate(byte[] bytes, int offset, int length) => Inflate(bytes.AsSpan(offset, length));
//Each block of compressed data begins with 3 header bits
// containing the following data:
public int AvailableBytes => _bytesUsed;
/// <summary>Copy the decompressed bytes to output buffer.</summary>
- public int CopyTo(Memory<byte> output)
+ public int CopyTo(Span<byte> output)
{
int copy_end;
{
// this means we need to copy two parts separately
// copy the taillen bytes from the end of the output window
- _window.AsSpan(WindowSize - tailLen, tailLen).CopyTo(output.Span);
+ _window.AsSpan(WindowSize - tailLen, tailLen).CopyTo(output);
output = output.Slice(tailLen, copy_end);
}
- _window.AsSpan(copy_end - output.Length, output.Length).CopyTo(output.Span);
+ _window.AsSpan(copy_end - output.Length, output.Length).CopyTo(output);
_bytesUsed -= copied;
Debug.Assert(_bytesUsed >= 0, "check this function and find why we copied more bytes than we have");
return copied;
}
-
- /// <summary>Copy the decompressed bytes to output array.</summary>
- public int CopyTo(byte[] output, int offset, int length)
- {
- return CopyTo(output.AsMemory(offset, length));
- }
}
}
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
namespace System.IO.Compression
{
_position += source.Length;
}
+ public override void WriteByte(byte value) =>
+ Write(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
+
+ public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ {
+ ValidateBufferArguments(buffer, offset, count);
+ return WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken).AsTask();
+ }
+
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
+ {
+ ThrowIfDisposed();
+ Debug.Assert(CanWrite);
+
+ return !buffer.IsEmpty ?
+ Core(buffer, cancellationToken) :
+ default;
+
+ async ValueTask Core(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
+ {
+ if (!_everWritten)
+ {
+ _everWritten = true;
+ // write local header, we are good to go
+ _usedZip64inLH = _entry.WriteLocalFileHeader(isEmptyFile: false);
+ }
+
+ await _crcSizeStream.WriteAsync(buffer, cancellationToken).ConfigureAwait(false);
+ _position += buffer.Length;
+ }
+ }
+
public override void Flush()
{
ThrowIfDisposed();
_crcSizeStream.Flush();
}
+ public override Task FlushAsync(CancellationToken cancellationToken)
+ {
+ ThrowIfDisposed();
+ Debug.Assert(CanWrite);
+
+ return _crcSizeStream.FlushAsync(cancellationToken);
+ }
+
protected override void Dispose(bool disposing)
{
if (disposing && !_isDisposed)
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
namespace System.IO.Compression
{
return _baseStream.Read(buffer, offset, count);
}
+ public override int Read(Span<byte> buffer)
+ {
+ ThrowIfDisposed();
+ ThrowIfCantRead();
+
+ return _baseStream.Read(buffer);
+ }
+
+ public override int ReadByte()
+ {
+ ThrowIfDisposed();
+ ThrowIfCantRead();
+
+ return _baseStream.ReadByte();
+ }
+
+ public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ {
+ ThrowIfDisposed();
+ ThrowIfCantRead();
+
+ return _baseStream.ReadAsync(buffer, offset, count, cancellationToken);
+ }
+
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
+ {
+ ThrowIfDisposed();
+ ThrowIfCantRead();
+
+ return _baseStream.ReadAsync(buffer, cancellationToken);
+ }
+
public override long Seek(long offset, SeekOrigin origin)
{
ThrowIfDisposed();
_baseStream.Write(source);
}
+ public override void WriteByte(byte value)
+ {
+ ThrowIfDisposed();
+ ThrowIfCantWrite();
+
+ _baseStream.WriteByte(value);
+ }
+
+ public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ {
+ ThrowIfDisposed();
+ ThrowIfCantWrite();
+
+ return _baseStream.WriteAsync(buffer, offset, count, cancellationToken);
+ }
+
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
+ {
+ ThrowIfDisposed();
+ ThrowIfCantWrite();
+
+ return _baseStream.WriteAsync(buffer, cancellationToken);
+ }
+
public override void Flush()
{
ThrowIfDisposed();
_baseStream.Flush();
}
+ public override Task FlushAsync(CancellationToken cancellationToken)
+ {
+ ThrowIfDisposed();
+ ThrowIfCantWrite();
+
+ return _baseStream.FlushAsync(cancellationToken);
+ }
+
protected override void Dispose(bool disposing)
{
if (disposing && !_isDisposed)
return ret;
}
+ public override int ReadByte()
+ {
+ byte b = default;
+ return Read(MemoryMarshal.CreateSpan(ref b, 1)) == 1 ? b : -1;
+ }
+
+ public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ {
+ ValidateBufferArguments(buffer, offset, count);
+ return ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
+ }
+
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
+ {
+ ThrowIfDisposed();
+ ThrowIfCantRead();
+ return Core(buffer, cancellationToken);
+
+ async ValueTask<int> Core(Memory<byte> buffer, CancellationToken cancellationToken)
+ {
+ if (_superStream.Position != _positionInSuperStream)
+ {
+ _superStream.Seek(_positionInSuperStream, SeekOrigin.Begin);
+ }
+
+ if (_positionInSuperStream > _endInSuperStream - buffer.Length)
+ {
+ buffer = buffer.Slice(0, (int)(_endInSuperStream - _positionInSuperStream));
+ }
+
+ int ret = await _superStream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
+
+ _positionInSuperStream += ret;
+ return ret;
+ }
+ }
+
public override long Seek(long offset, SeekOrigin origin)
{
ThrowIfDisposed();
_position += source.Length;
}
+ public override void WriteByte(byte value) =>
+ Write(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
+
+ public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ {
+ ValidateBufferArguments(buffer, offset, count);
+ return WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken).AsTask();
+ }
+
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
+ {
+ ThrowIfDisposed();
+ Debug.Assert(CanWrite);
+
+ return !buffer.IsEmpty ?
+ Core(buffer, cancellationToken) :
+ default;
+
+ async ValueTask Core(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
+ {
+ if (!_everWritten)
+ {
+ _initialPosition = _baseBaseStream.Position;
+ _everWritten = true;
+ }
+
+ _checksum = Crc32Helper.UpdateCrc32(_checksum, buffer.Span);
+
+ await _baseStream.WriteAsync(buffer, cancellationToken).ConfigureAwait(false);
+ _position += buffer.Length;
+ }
+ }
+
public override void Flush()
{
ThrowIfDisposed();
_baseStream.Flush();
}
+ public override Task FlushAsync(CancellationToken cancellationToken)
+ {
+ ThrowIfDisposed();
+ return _baseStream.FlushAsync(cancellationToken);
+ }
+
protected override void Dispose(bool disposing)
{
if (disposing && !_isDisposed)