mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-24 07:54:39 +00:00
async deflate 64
This commit is contained in:
@@ -6,6 +6,8 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Zip;
|
||||
using SharpCompress.IO;
|
||||
@@ -143,6 +145,106 @@ public sealed class Deflate64Stream : Stream, IStreamStack
|
||||
return count - remainingCount;
|
||||
}
|
||||
|
||||
public override async Task<int> ReadAsync(
|
||||
byte[] array,
|
||||
int offset,
|
||||
int count,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
ValidateParameters(array, offset, count);
|
||||
EnsureNotDisposed();
|
||||
|
||||
int bytesRead;
|
||||
var currentOffset = offset;
|
||||
var remainingCount = count;
|
||||
|
||||
while (true)
|
||||
{
|
||||
bytesRead = _inflater.Inflate(array, currentOffset, remainingCount);
|
||||
currentOffset += bytesRead;
|
||||
remainingCount -= bytesRead;
|
||||
|
||||
if (remainingCount == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (_inflater.Finished())
|
||||
{
|
||||
// if we finished decompressing, we can't have anything left in the outputwindow.
|
||||
Debug.Assert(
|
||||
_inflater.AvailableOutput == 0,
|
||||
"We should have copied all stuff out!"
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
var bytes = await _stream
|
||||
.ReadAsync(_buffer, 0, _buffer.Length, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (bytes <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (bytes > _buffer.Length)
|
||||
{
|
||||
// The stream is either malicious or poorly implemented and returned a number of
|
||||
// bytes larger than the buffer supplied to it.
|
||||
throw new InvalidFormatException("Deflate64: invalid data");
|
||||
}
|
||||
|
||||
_inflater.SetInput(_buffer, 0, bytes);
|
||||
}
|
||||
|
||||
return count - remainingCount;
|
||||
}
|
||||
|
||||
#if !NETFRAMEWORK && !NETSTANDARD2_0
|
||||
public override async ValueTask<int> ReadAsync(
|
||||
Memory<byte> buffer,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
|
||||
// InflaterManaged doesn't have a Span-based Inflate method, so we need to work with arrays
|
||||
// For large buffers, we could rent from ArrayPool, but for simplicity we'll use the buffer's array if available
|
||||
if (
|
||||
System.Runtime.InteropServices.MemoryMarshal.TryGetArray<byte>(
|
||||
buffer,
|
||||
out var arraySegment
|
||||
)
|
||||
)
|
||||
{
|
||||
// Fast path: the Memory<byte> is backed by an array
|
||||
return await ReadAsync(
|
||||
arraySegment.Array!,
|
||||
arraySegment.Offset,
|
||||
arraySegment.Count,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Slow path: rent a temporary array
|
||||
var tempBuffer = System.Buffers.ArrayPool<byte>.Shared.Rent(buffer.Length);
|
||||
try
|
||||
{
|
||||
var bytesRead = await ReadAsync(tempBuffer, 0, buffer.Length, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
tempBuffer.AsMemory(0, bytesRead).CopyTo(buffer);
|
||||
return bytesRead;
|
||||
}
|
||||
finally
|
||||
{
|
||||
System.Buffers.ArrayPool<byte>.Shared.Return(tempBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private void ValidateParameters(byte[] array, int offset, int count)
|
||||
{
|
||||
if (array is null)
|
||||
|
||||
@@ -100,51 +100,61 @@ public class Zip64AsyncTests : WriterTests
|
||||
{
|
||||
filename = Path.Combine(SCRATCH2_FILES_PATH, filename);
|
||||
|
||||
if (File.Exists(filename))
|
||||
try
|
||||
{
|
||||
File.Delete(filename);
|
||||
}
|
||||
if (File.Exists(filename))
|
||||
{
|
||||
File.Delete(filename);
|
||||
}
|
||||
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
await CreateZipArchiveAsync(
|
||||
filename,
|
||||
files,
|
||||
filesize,
|
||||
writeChunkSize,
|
||||
setZip64,
|
||||
forwardOnly
|
||||
);
|
||||
}
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
await CreateZipArchiveAsync(
|
||||
filename,
|
||||
files,
|
||||
filesize,
|
||||
writeChunkSize,
|
||||
setZip64,
|
||||
forwardOnly
|
||||
);
|
||||
}
|
||||
|
||||
var resForward = await ReadForwardOnlyAsync(filename);
|
||||
if (resForward.Item1 != files)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Incorrect number of items reported: {resForward.Item1}, should have been {files}"
|
||||
);
|
||||
}
|
||||
var resForward = await ReadForwardOnlyAsync(filename);
|
||||
if (resForward.Item1 != files)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Incorrect number of items reported: {resForward.Item1}, should have been {files}"
|
||||
);
|
||||
}
|
||||
|
||||
if (resForward.Item2 != files * filesize)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Incorrect combined size reported: {resForward.Item2}, should have been {files * filesize}"
|
||||
);
|
||||
}
|
||||
if (resForward.Item2 != files * filesize)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Incorrect combined size reported: {resForward.Item2}, should have been {files * filesize}"
|
||||
);
|
||||
}
|
||||
|
||||
var resArchive = ReadArchive(filename);
|
||||
if (resArchive.Item1 != files)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Incorrect number of items reported: {resArchive.Item1}, should have been {files}"
|
||||
);
|
||||
}
|
||||
var resArchive = ReadArchive(filename);
|
||||
if (resArchive.Item1 != files)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Incorrect number of items reported: {resArchive.Item1}, should have been {files}"
|
||||
);
|
||||
}
|
||||
|
||||
if (resArchive.Item2 != files * filesize)
|
||||
if (resArchive.Item2 != files * filesize)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Incorrect number of items reported: {resArchive.Item2}, should have been {files * filesize}"
|
||||
);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Incorrect number of items reported: {resArchive.Item2}, should have been {files * filesize}"
|
||||
);
|
||||
if (File.Exists(filename))
|
||||
{
|
||||
File.Delete(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user