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.
///
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