From 74f36a49778fcb11cd02ab95ba85d86fdf8787bd Mon Sep 17 00:00:00 2001 From: Richard Webb Date: Sun, 14 Feb 2021 16:39:47 +0000 Subject: [PATCH 1/2] Add an async version of ReadRequestedBytes --- .../Core/StreamUtils.cs | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/src/ICSharpCode.SharpZipLib/Core/StreamUtils.cs b/src/ICSharpCode.SharpZipLib/Core/StreamUtils.cs index 47de6e26e..5e437f6b1 100644 --- a/src/ICSharpCode.SharpZipLib/Core/StreamUtils.cs +++ b/src/ICSharpCode.SharpZipLib/Core/StreamUtils.cs @@ -66,16 +66,8 @@ public static void ReadFully(Stream stream, byte[] buffer, int offset, int count } } - /// - /// Read as much data as possible from a ", up to the requested number of bytes - /// - /// The stream to read data from. - /// The buffer to store data in. - /// The offset at which to begin storing data. - /// The number of bytes of data to store. - /// Required parameter is null - /// and or are invalid. - public static int ReadRequestedBytes(Stream stream, byte[] buffer, int offset, int count) + // A helper function to share between the async and sync versions of ReadRequestedBytes + private static void ValidateArgumentsForRead(Stream stream, byte[] buffer, int offset, int count) { if (stream == null) { @@ -97,7 +89,23 @@ public static int ReadRequestedBytes(Stream stream, byte[] buffer, int offset, i { throw new ArgumentOutOfRangeException(nameof(count)); } + } + /// + /// Read as much data as possible from a ", up to the requested number of bytes + /// + /// The stream to read data from. + /// The buffer to store data in. + /// The offset at which to begin storing data. + /// The number of bytes of data to store. + /// Required parameter is null + /// and or are invalid. + public static int ReadRequestedBytes(Stream stream, byte[] buffer, int offset, int count) + { + // Common validation function + ValidateArgumentsForRead(stream, buffer, offset, count); + + // read the data using Read int totalReadCount = 0; while (count > 0) { @@ -114,6 +122,38 @@ public static int ReadRequestedBytes(Stream stream, byte[] buffer, int offset, i return totalReadCount; } + /// + /// Read as much data as possible from a ", up to the requested number of bytes + /// + /// The stream to read data from. + /// The buffer to store data in. + /// The offset at which to begin storing data. + /// The number of bytes of data to store. + /// The token to monitor for cancellation requests. + /// Required parameter is null + /// and or are invalid. + public static async Task ReadRequestedBytesAsync(Stream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + // Common validation function + ValidateArgumentsForRead(stream, buffer, offset, count); + + // read the data using ReadAsync + int totalReadCount = 0; + while (count > 0) + { + int readCount = await stream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + if (readCount <= 0) + { + break; + } + offset += readCount; + count -= readCount; + totalReadCount += readCount; + } + + return totalReadCount; + } + /// /// Copy the contents of one to another. /// From f8b19ed4c70ae9a173fee56b5e1ab02ce7c9b8b9 Mon Sep 17 00:00:00 2001 From: Richard Webb Date: Sat, 8 May 2021 22:51:21 +0100 Subject: [PATCH 2/2] Make ZipAESStream.ReadAsync do async stream reads --- .../Encryption/ZipAESStream.cs | 61 +++++++++++++------ 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/src/ICSharpCode.SharpZipLib/Encryption/ZipAESStream.cs b/src/ICSharpCode.SharpZipLib/Encryption/ZipAESStream.cs index 80ce0b4ab..09dd3a6be 100644 --- a/src/ICSharpCode.SharpZipLib/Encryption/ZipAESStream.cs +++ b/src/ICSharpCode.SharpZipLib/Encryption/ZipAESStream.cs @@ -67,6 +67,44 @@ public ZipAESStream(Stream stream, ZipAESTransform transform, CryptoStreamMode m /// and advances the position within the stream by the number of bytes read. /// public override int Read(byte[] buffer, int offset, int count) + { + // If we have buffered data, read that first + int nBytes = ReadDataFromBuffer(buffer, ref offset, ref count); + + // If we've read the requested amount of data, return just that + if (count == 0) + return nBytes; + + // Read more data from the input, if available + if (_slideBuffer != null) + { + nBytes += ReadAndTransformAsync(buffer, offset, count, false, default).GetAwaiter().GetResult(); + } + + return nBytes; + } + + /// + public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + // If we have buffered data, read that first + int nBytes = ReadDataFromBuffer(buffer, ref offset, ref count); + + // If we've read the requested amount of data, return just that + if (count == 0) + return nBytes; + + // Read more data from the input, if available + if (_slideBuffer != null) + { + nBytes += await ReadAndTransformAsync(buffer, offset, count, true, cancellationToken).ConfigureAwait(false); + } + + return nBytes; + } + + // Read up to the requested amount of data from the buffer + private int ReadDataFromBuffer(byte[] buffer, ref int offset, ref int count) { // Nothing to do if (count == 0) @@ -78,30 +116,15 @@ public override int Read(byte[] buffer, int offset, int count) { nBytes = ReadBufferedData(buffer, offset, count); - // Read all requested data from the buffer - if (nBytes == count) - return nBytes; - offset += nBytes; count -= nBytes; } - // Read more data from the input, if available - if (_slideBuffer != null) - nBytes += ReadAndTransform(buffer, offset, count); - return nBytes; } - /// - public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - var readCount = Read(buffer, offset, count); - return Task.FromResult(readCount); - } - // Read data from the underlying stream and decrypt it - private int ReadAndTransform(byte[] buffer, int offset, int count) + private async Task ReadAndTransformAsync(byte[] buffer, int offset, int count, bool useAsync, CancellationToken cancellationToken) { int nBytes = 0; while (nBytes < count) @@ -126,7 +149,11 @@ private int ReadAndTransform(byte[] buffer, int offset, int count) _slideBufFreePos -= _slideBufStartPos; // Note the -= _slideBufStartPos = 0; } - int obtained = StreamUtils.ReadRequestedBytes(_stream, _slideBuffer, _slideBufFreePos, lengthToRead); + + int obtained = useAsync ? + await StreamUtils.ReadRequestedBytesAsync(_stream, _slideBuffer, _slideBufFreePos, lengthToRead, cancellationToken).ConfigureAwait(false) : + StreamUtils.ReadRequestedBytes(_stream, _slideBuffer, _slideBufFreePos, lengthToRead); + _slideBufFreePos += obtained; // Recalculate how much data we now have