diff --git a/src/SharpCompress/Common/AsyncBinaryReader.cs b/src/SharpCompress/Common/AsyncBinaryReader.cs index 2a6eb92c..51da5d5c 100644 --- a/src/SharpCompress/Common/AsyncBinaryReader.cs +++ b/src/SharpCompress/Common/AsyncBinaryReader.cs @@ -29,57 +29,35 @@ namespace SharpCompress.Common public async ValueTask ReadByteAsync(CancellationToken ct = default) { - await ReadExactAsync(_buffer, 0, 1, ct).ConfigureAwait(false); + await _stream.ReadExactAsync(_buffer, 0, 1, ct).ConfigureAwait(false); return _buffer[0]; } public async ValueTask ReadUInt16Async(CancellationToken ct = default) { - await ReadExactAsync(_buffer, 0, 2, ct).ConfigureAwait(false); + await _stream.ReadExactAsync(_buffer, 0, 2, ct).ConfigureAwait(false); return BinaryPrimitives.ReadUInt16LittleEndian(_buffer); } public async ValueTask ReadUInt32Async(CancellationToken ct = default) { - await ReadExactAsync(_buffer, 0, 4, ct).ConfigureAwait(false); + await _stream.ReadExactAsync(_buffer, 0, 4, ct).ConfigureAwait(false); return BinaryPrimitives.ReadUInt32LittleEndian(_buffer); } public async ValueTask ReadUInt64Async(CancellationToken ct = default) { - await ReadExactAsync(_buffer, 0, 8, ct).ConfigureAwait(false); + await _stream.ReadExactAsync(_buffer, 0, 8, ct).ConfigureAwait(false); return BinaryPrimitives.ReadUInt64LittleEndian(_buffer); } public async ValueTask ReadBytesAsync(int count, CancellationToken ct = default) { var result = new byte[count]; - await ReadExactAsync(result, 0, count, ct).ConfigureAwait(false); + await _stream.ReadExactAsync(result, 0, count, ct).ConfigureAwait(false); return result; } - private async ValueTask ReadExactAsync( - byte[] destination, - int offset, - int length, - CancellationToken ct - ) - { - var read = 0; - while (read < length) - { - var n = await _stream - .ReadAsync(destination, offset + read, length - read, ct) - .ConfigureAwait(false); - if (n == 0) - { - throw new EndOfStreamException(); - } - - read += n; - } - } - public void Dispose() { if (_disposed) diff --git a/src/SharpCompress/Compressors/LZMA/Utilites/Utils.cs b/src/SharpCompress/Compressors/LZMA/Utilites/Utils.cs index 19b0f374..b57cd53f 100644 --- a/src/SharpCompress/Compressors/LZMA/Utilites/Utils.cs +++ b/src/SharpCompress/Compressors/LZMA/Utilites/Utils.cs @@ -53,39 +53,4 @@ internal static class Utils throw new InvalidOperationException("Assertion failed."); } } - - public static void ReadExact(this Stream stream, byte[] buffer, int offset, int length) - { - if (stream is null) - { - throw new ArgumentNullException(nameof(stream)); - } - - if (buffer is null) - { - throw new ArgumentNullException(nameof(buffer)); - } - - if (offset < 0 || offset > buffer.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - - if (length < 0 || length > buffer.Length - offset) - { - throw new ArgumentOutOfRangeException(nameof(length)); - } - - while (length > 0) - { - var fetched = stream.Read(buffer, offset, length); - if (fetched <= 0) - { - throw new EndOfStreamException(); - } - - offset += fetched; - length -= fetched; - } - } } diff --git a/src/SharpCompress/Polyfills/BinaryReaderExtensions.cs b/src/SharpCompress/Polyfills/BinaryReaderExtensions.cs index a030d4bc..d34771cf 100644 --- a/src/SharpCompress/Polyfills/BinaryReaderExtensions.cs +++ b/src/SharpCompress/Polyfills/BinaryReaderExtensions.cs @@ -11,23 +11,11 @@ public static class BinaryReaderExtensions { public async Task ReadByteAsync(CancellationToken cancellationToken = default) { - var buffer = ArrayPool.Shared.Rent(1); - try - { - var bytesRead = await reader - .BaseStream.ReadAsync(buffer, 0, 1, cancellationToken) - .ConfigureAwait(false); - if (bytesRead != 1) - { - throw new EndOfStreamException(); - } - - return buffer[0]; - } - finally - { - ArrayPool.Shared.Return(buffer); - } + var buffer = new byte[1]; + await reader + .BaseStream.ReadExactAsync(buffer, 0, 1, cancellationToken) + .ConfigureAwait(false); + return buffer[0]; } public async Task ReadBytesAsync( @@ -35,24 +23,11 @@ public static class BinaryReaderExtensions CancellationToken cancellationToken = default ) { - var buffer = ArrayPool.Shared.Rent(count); - try - { - var bytesRead = await reader - .BaseStream.ReadAsync(buffer, 0, 1, cancellationToken) - .ConfigureAwait(false); - if (bytesRead != count) - { - throw new EndOfStreamException(); - } - var bytes = new byte[count]; - System.Buffer.BlockCopy(buffer, 0, bytes, 0, count); - return bytes; - } - finally - { - ArrayPool.Shared.Return(buffer); - } + var bytes = new byte[count]; + await reader + .BaseStream.ReadExactAsync(bytes, 0, count, cancellationToken) + .ConfigureAwait(false); + return bytes; } } } diff --git a/src/SharpCompress/Polyfills/StreamExtensions.cs b/src/SharpCompress/Polyfills/StreamExtensions.cs index bd41ac75..ab617e95 100644 --- a/src/SharpCompress/Polyfills/StreamExtensions.cs +++ b/src/SharpCompress/Polyfills/StreamExtensions.cs @@ -98,20 +98,9 @@ public static class StreamExtensions int offset, int count, CancellationToken cancellationToken - ) - { - var totalRead = 0; - while (totalRead < count) - { - var read = await stream - .ReadAsync(buffer, offset + totalRead, count - totalRead, cancellationToken) - .ConfigureAwait(false); - if (read == 0) - { - throw new EndOfStreamException(); - } - totalRead += read; - } - } + ) => + await stream + .ReadExactAsync(buffer, offset, count, cancellationToken) + .ConfigureAwait(false); } } diff --git a/src/SharpCompress/Utility.cs b/src/SharpCompress/Utility.cs index ea0faa2a..4db9d340 100644 --- a/src/SharpCompress/Utility.cs +++ b/src/SharpCompress/Utility.cs @@ -273,6 +273,33 @@ internal static class Utility } } +#if NET60_OR_GREATER + public bool ReadFully(byte[] buffer) + { + try + { + source.ReadExactly(buffer); + return true; + } + catch (EndOfStreamException) + { + return false; + } + } + + public bool ReadFully(Span buffer) + { + try + { + source.ReadExactly(buffer); + return true; + } + catch (EndOfStreamException) + { + return false; + } + } +#else public bool ReadFully(byte[] buffer) { var total = 0; @@ -302,6 +329,7 @@ internal static class Utility } return (total >= buffer.Length); } +#endif public async Task ReadFullyAsync( byte[] buffer, @@ -354,36 +382,89 @@ internal static class Utility } } -#if NET60_OR_GREATER - - public static bool ReadFully(this Stream stream, byte[] buffer) + /// + /// Read exactly the requested number of bytes from a stream. Throws EndOfStreamException if not enough data is available. + /// + public static void ReadExact(this Stream stream, byte[] buffer, int offset, int length) { - try + if (stream is null) { - stream.ReadExactly(buffer); - return true; + throw new ArgumentNullException(nameof(stream)); } - catch (EndOfStreamException) + + if (buffer is null) { - return false; + throw new ArgumentNullException(nameof(buffer)); + } + + if (offset < 0 || offset > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + + if (length < 0 || length > buffer.Length - offset) + { + throw new ArgumentOutOfRangeException(nameof(length)); + } + + while (length > 0) + { + var fetched = stream.Read(buffer, offset, length); + if (fetched <= 0) + { + throw new EndOfStreamException(); + } + + offset += fetched; + length -= fetched; } } - public static bool ReadFully(this Stream stream, Span buffer) + /// + /// Read exactly the requested number of bytes from a stream asynchronously. Throws EndOfStreamException if not enough data is available. + /// + public static async Task ReadExactAsync( + this Stream stream, + byte[] buffer, + int offset, + int length, + CancellationToken cancellationToken = default + ) { - try + if (stream is null) { - stream.ReadExactly(buffer); - return true; + throw new ArgumentNullException(nameof(stream)); } - catch (EndOfStreamException) + + if (buffer is null) { - return false; + throw new ArgumentNullException(nameof(buffer)); + } + + if (offset < 0 || offset > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + + if (length < 0 || length > buffer.Length - offset) + { + throw new ArgumentOutOfRangeException(nameof(length)); + } + + while (length > 0) + { + var fetched = await stream + .ReadAsync(buffer, offset, length, cancellationToken) + .ConfigureAwait(false); + if (fetched <= 0) + { + throw new EndOfStreamException(); + } + + offset += fetched; + length -= fetched; } } -#else - -#endif public static string TrimNulls(this string source) => source.Replace('\0', ' ').Trim();