more async await

This commit is contained in:
Adam Hathcock
2021-02-01 08:34:12 +00:00
parent bcdfd992a3
commit 2b4f02997e
27 changed files with 507 additions and 397 deletions

View File

@@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Readers;
using SharpCompress.Writers;
@@ -137,11 +139,11 @@ namespace SharpCompress.Archives
return false;
}
public void SaveTo(Stream stream, WriterOptions options)
public async Task SaveToAsync(Stream stream, WriterOptions options)
{
//reset streams of new entries
newEntries.Cast<IWritableArchiveEntry>().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin));
SaveTo(stream, options, OldEntries, newEntries);
await SaveToAsync(stream, options, OldEntries, newEntries);
}
protected TEntry CreateEntry(string key, Stream source, long size, DateTime? modified,
@@ -157,7 +159,8 @@ namespace SharpCompress.Archives
protected abstract TEntry CreateEntryInternal(string key, Stream source, long size, DateTime? modified,
bool closeStream);
protected abstract void SaveTo(Stream stream, WriterOptions options, IEnumerable<TEntry> oldEntries, IEnumerable<TEntry> newEntries);
protected abstract Task SaveToAsync(Stream stream, WriterOptions options, IEnumerable<TEntry> oldEntries, IEnumerable<TEntry> newEntries,
CancellationToken cancellationToken = default);
public override void Dispose()
{

View File

@@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Common.GZip;
using SharpCompress.Readers;
@@ -82,17 +84,15 @@ namespace SharpCompress.Archives.GZip
return IsGZipFile(stream);
}
public void SaveTo(string filePath)
public Task SaveToAsync(string filePath)
{
SaveTo(new FileInfo(filePath));
return SaveToAsync(new FileInfo(filePath));
}
public void SaveTo(FileInfo fileInfo)
public async Task SaveToAsync(FileInfo fileInfo)
{
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
{
SaveTo(stream, new WriterOptions(CompressionType.GZip));
}
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
await SaveToAsync(stream, new WriterOptions(CompressionType.GZip));
}
public static bool IsGZipFile(Stream stream)
@@ -139,24 +139,22 @@ namespace SharpCompress.Archives.GZip
return new GZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream);
}
protected override void SaveTo(Stream stream, WriterOptions options,
IEnumerable<GZipArchiveEntry> oldEntries,
IEnumerable<GZipArchiveEntry> newEntries)
protected override async Task SaveToAsync(Stream stream, WriterOptions options,
IEnumerable<GZipArchiveEntry> oldEntries,
IEnumerable<GZipArchiveEntry> newEntries,
CancellationToken cancellationToken = default)
{
if (Entries.Count > 1)
{
throw new InvalidOperationException("Only one entry is allowed in a GZip Archive");
}
using (var writer = new GZipWriter(stream, new GZipWriterOptions(options)))
await using var writer = new GZipWriter(stream, new GZipWriterOptions(options));
foreach (var entry in oldEntries.Concat(newEntries)
.Where(x => !x.IsDirectory))
{
foreach (var entry in oldEntries.Concat(newEntries)
.Where(x => !x.IsDirectory))
{
using (var entryStream = entry.OpenEntryStream())
{
writer.Write(entry.Key, entryStream, entry.LastModifiedTime);
}
}
await using var entryStream = entry.OpenEntryStream();
await writer.WriteAsync(entry.Key, entryStream, entry.LastModifiedTime, cancellationToken);
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Threading.Tasks;
using SharpCompress.Writers;
namespace SharpCompress.Archives
@@ -10,7 +11,7 @@ namespace SharpCompress.Archives
IArchiveEntry AddEntry(string key, Stream source, bool closeStream, long size = 0, DateTime? modified = null);
void SaveTo(Stream stream, WriterOptions options);
Task SaveToAsync(Stream stream, WriterOptions options);
/// <summary>
/// Use this to pause entry rebuilding when adding large collections of entries. Dispose when complete. A using statement is recommended.

View File

@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Threading.Tasks;
using SharpCompress.Writers;
namespace SharpCompress.Archives
@@ -18,17 +19,15 @@ namespace SharpCompress.Archives
fileInfo.LastWriteTime);
}
public static void SaveTo(this IWritableArchive writableArchive, string filePath, WriterOptions options)
public static Task SaveToAsync(this IWritableArchive writableArchive, string filePath, WriterOptions options)
{
writableArchive.SaveTo(new FileInfo(filePath), options);
return writableArchive.SaveToAsync(new FileInfo(filePath), options);
}
public static void SaveTo(this IWritableArchive writableArchive, FileInfo fileInfo, WriterOptions options)
public static async Task SaveToAsync(this IWritableArchive writableArchive, FileInfo fileInfo, WriterOptions options)
{
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
{
writableArchive.SaveTo(stream, options);
}
await using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
await writableArchive.SaveToAsync(stream, options);
}
public static void AddAllFromDirectory(

View File

@@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Common.Tar;
using SharpCompress.Common.Tar.Headers;
@@ -59,10 +61,9 @@ namespace SharpCompress.Archives.Tar
{
return false;
}
using (Stream stream = fileInfo.OpenRead())
{
return IsTarFile(stream);
}
using Stream stream = fileInfo.OpenRead();
return IsTarFile(stream);
}
public static bool IsTarFile(Stream stream)
@@ -170,20 +171,17 @@ namespace SharpCompress.Archives.Tar
closeStream);
}
protected override void SaveTo(Stream stream, WriterOptions options,
IEnumerable<TarArchiveEntry> oldEntries,
IEnumerable<TarArchiveEntry> newEntries)
protected override async Task SaveToAsync(Stream stream, WriterOptions options,
IEnumerable<TarArchiveEntry> oldEntries,
IEnumerable<TarArchiveEntry> newEntries,
CancellationToken cancellationToken = default)
{
using (var writer = new TarWriter(stream, new TarWriterOptions(options)))
await using var writer = new TarWriter(stream, new TarWriterOptions(options));
foreach (var entry in oldEntries.Concat(newEntries)
.Where(x => !x.IsDirectory))
{
foreach (var entry in oldEntries.Concat(newEntries)
.Where(x => !x.IsDirectory))
{
using (var entryStream = entry.OpenEntryStream())
{
writer.Write(entry.Key, entryStream, entry.LastModifiedTime, entry.Size);
}
}
await using var entryStream = entry.OpenEntryStream();
await writer.WriteAsync(entry.Key, entryStream, entry.LastModifiedTime, cancellationToken);
}
}

View File

@@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Common.Zip;
using SharpCompress.Common.Zip.Headers;
@@ -163,23 +165,24 @@ namespace SharpCompress.Archives.Zip
}
}
public void SaveTo(Stream stream)
public Task SaveToAsync(Stream stream)
{
SaveTo(stream, new WriterOptions(CompressionType.Deflate));
return SaveToAsync(stream, new WriterOptions(CompressionType.Deflate));
}
protected override void SaveTo(Stream stream, WriterOptions options,
IEnumerable<ZipArchiveEntry> oldEntries,
IEnumerable<ZipArchiveEntry> newEntries)
protected override async Task SaveToAsync(Stream stream, WriterOptions options,
IEnumerable<ZipArchiveEntry> oldEntries,
IEnumerable<ZipArchiveEntry> newEntries,
CancellationToken cancellationToken = default)
{
using (var writer = new ZipWriter(stream, new ZipWriterOptions(options)))
await using (var writer = new ZipWriter(stream, new ZipWriterOptions(options)))
{
foreach (var entry in oldEntries.Concat(newEntries)
.Where(x => !x.IsDirectory))
{
using (var entryStream = entry.OpenEntryStream())
await using (var entryStream = entry.OpenEntryStream())
{
writer.Write(entry.Key, entryStream, entry.LastModifiedTime);
await writer.WriteAsync(entry.Key, entryStream, entry.LastModifiedTime, cancellationToken);
}
}
}

View File

@@ -1,5 +1,7 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace SharpCompress.Common
{
@@ -8,10 +10,11 @@ namespace SharpCompress.Common
/// <summary>
/// Extract to specific directory, retaining filename
/// </summary>
public static void WriteEntryToDirectory(IEntry entry,
public static async ValueTask WriteEntryToDirectoryAsync(IEntry entry,
string destinationDirectory,
ExtractionOptions? options,
Action<string, ExtractionOptions?> write)
Func<string, ExtractionOptions?, CancellationToken, ValueTask> write,
CancellationToken cancellationToken = default)
{
string destinationFileName;
string file = Path.GetFileName(entry.Key);
@@ -52,7 +55,7 @@ namespace SharpCompress.Common
{
throw new ExtractionException("Entry is trying to write a file outside of the destination directory.");
}
write(destinationFileName, options);
await write(destinationFileName, options, cancellationToken);
}
else if (options.ExtractFullPath && !Directory.Exists(destinationFileName))
{
@@ -60,11 +63,12 @@ namespace SharpCompress.Common
}
}
public static void WriteEntryToFile(IEntry entry, string destinationFileName,
public static async ValueTask WriteEntryToFileAsync(IEntry entry, string destinationFileName,
ExtractionOptions? options,
Action<string, FileMode> openAndWrite)
Func<string, FileMode, CancellationToken, ValueTask> openAndWrite,
CancellationToken cancellationToken = default)
{
if (entry.LinkTarget != null)
if (entry.LinkTarget is not null)
{
if (options?.WriteSymbolicLink is null)
{
@@ -85,7 +89,7 @@ namespace SharpCompress.Common
fm = FileMode.CreateNew;
}
openAndWrite(destinationFileName, fm);
await openAndWrite(destinationFileName, fm, cancellationToken);
entry.PreserveExtractionOptions(destinationFileName, options);
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace SharpCompress.Common.GZip
{
@@ -41,8 +42,9 @@ namespace SharpCompress.Common.GZip
internal override IEnumerable<FilePart> Parts => _filePart.AsEnumerable<FilePart>();
internal static IEnumerable<GZipEntry> GetEntries(Stream stream, OptionsBase options)
internal static async IAsyncEnumerable<GZipEntry> GetEntries(Stream stream, OptionsBase options)
{
await Task.CompletedTask;
yield return new GZipEntry(new GZipFilePart(stream, options.ArchiveEncoding));
}
}

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.IO;
@@ -12,8 +13,10 @@ namespace SharpCompress.Common.Zip
{
}
internal IEnumerable<ZipHeader> ReadStreamHeader(Stream stream)
internal async IAsyncEnumerable<ZipHeader> ReadStreamHeader(Stream stream)
{
//TODO async stream reader?
await Task.CompletedTask;
RewindableStream rewindableStream;
if (stream is RewindableStream rs)
@@ -27,7 +30,7 @@ namespace SharpCompress.Common.Zip
while (true)
{
ZipHeader? header;
BinaryReader reader = new BinaryReader(rewindableStream);
BinaryReader reader = new(rewindableStream);
if (_lastEntryHeader != null &&
(FlagUtility.HasFlag(_lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor) || _lastEntryHeader.IsZip64))
{

View File

@@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
namespace SharpCompress.Readers
@@ -14,7 +16,7 @@ namespace SharpCompress.Readers
where TVolume : Volume
{
private bool completed;
private IEnumerator<TEntry>? entriesForCurrentReadStream;
private IAsyncEnumerator<TEntry>? entriesForCurrentReadStream;
private bool wroteCurrentEntry;
public event EventHandler<ReaderExtractionEventArgs<IEntry>>? EntryExtractionProgress;
@@ -40,13 +42,13 @@ namespace SharpCompress.Readers
/// <summary>
/// Current file entry
/// </summary>
public TEntry Entry => entriesForCurrentReadStream!.Current;
public TEntry? Entry => entriesForCurrentReadStream?.Current ?? default;
#region IDisposable Members
public void Dispose()
public async ValueTask DisposeAsync()
{
entriesForCurrentReadStream?.Dispose();
await (entriesForCurrentReadStream?.DisposeAsync() ?? new ValueTask(Task.CompletedTask));
Volume?.Dispose();
}
@@ -67,7 +69,7 @@ namespace SharpCompress.Readers
}
}
public bool MoveToNextEntry()
public async ValueTask<bool> MoveToNextEntry()
{
if (completed)
{
@@ -79,14 +81,14 @@ namespace SharpCompress.Readers
}
if (entriesForCurrentReadStream is null)
{
return LoadStreamForReading(RequestInitialStream());
return await LoadStreamForReading(RequestInitialStream());
}
if (!wroteCurrentEntry)
{
SkipEntry();
}
wroteCurrentEntry = false;
if (NextEntryForCurrentStream())
if (await NextEntryForCurrentStream())
{
return true;
}
@@ -94,17 +96,17 @@ namespace SharpCompress.Readers
return false;
}
protected bool LoadStreamForReading(Stream stream)
protected async Task<bool> LoadStreamForReading(Stream stream)
{
entriesForCurrentReadStream?.Dispose();
if ((stream is null) || (!stream.CanRead))
await (entriesForCurrentReadStream?.DisposeAsync() ?? new ValueTask(Task.CompletedTask));
if (stream is null || !stream.CanRead)
{
throw new MultipartStreamRequiredException("File is split into multiple archives: '"
+ Entry.Key +
+ (Entry?.Key ?? "unknown") +
"'. A new readable stream is required. Use Cancel if it was intended.");
}
entriesForCurrentReadStream = GetEntries(stream).GetEnumerator();
return entriesForCurrentReadStream.MoveNext();
entriesForCurrentReadStream = GetEntries(stream).GetAsyncEnumerator();
return await (entriesForCurrentReadStream?.MoveNextAsync() ?? new ValueTask<bool>(Task.FromResult(false)));
}
protected virtual Stream RequestInitialStream()
@@ -112,18 +114,18 @@ namespace SharpCompress.Readers
return Volume.Stream;
}
internal virtual bool NextEntryForCurrentStream()
internal virtual async ValueTask<bool> NextEntryForCurrentStream()
{
return entriesForCurrentReadStream!.MoveNext();
return await (entriesForCurrentReadStream?.MoveNextAsync() ?? new ValueTask<bool>(Task.FromResult(false)));
}
protected abstract IEnumerable<TEntry> GetEntries(Stream stream);
protected abstract IAsyncEnumerable<TEntry> GetEntries(Stream stream);
#region Entry Skip/Write
private void SkipEntry()
{
if (!Entry.IsDirectory)
if (Entry?.IsDirectory == true)
{
Skip();
}
@@ -131,6 +133,10 @@ namespace SharpCompress.Readers
private void Skip()
{
if (Entry is null)
{
return;
}
if (ArchiveType != ArchiveType.Rar
&& !Entry.IsSolid
&& Entry.CompressedSize > 0)
@@ -154,7 +160,7 @@ namespace SharpCompress.Readers
}
}
public void WriteEntryTo(Stream writableStream)
public async ValueTask WriteEntryToAsync(Stream writableStream, CancellationToken cancellationToken = default)
{
if (wroteCurrentEntry)
{
@@ -165,16 +171,20 @@ namespace SharpCompress.Readers
throw new ArgumentNullException("A writable Stream was required. Use Cancel if that was intended.");
}
Write(writableStream);
await WriteAsync(writableStream, cancellationToken);
wroteCurrentEntry = true;
}
internal void Write(Stream writeStream)
internal async ValueTask WriteAsync(Stream writeStream, CancellationToken cancellationToken)
{
if (Entry is null)
{
throw new ArgumentException("Entry is null");
}
var streamListener = this as IReaderExtractionListener;
using (Stream s = OpenEntryStream())
{
s.TransferTo(writeStream, Entry, streamListener);
await s.TransferToAsync(writeStream, Entry, streamListener, cancellationToken);
}
}
@@ -199,12 +209,16 @@ namespace SharpCompress.Readers
protected virtual EntryStream GetEntryStream()
{
if (Entry is null)
{
throw new ArgumentException("Entry is null");
}
return CreateEntryStream(Entry.Parts.First().GetCompressedStream());
}
#endregion
IEntry IReader.Entry => Entry;
IEntry? IReader.Entry => Entry;
void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes)
{

View File

@@ -31,7 +31,7 @@ namespace SharpCompress.Readers.GZip
#endregion Open
protected override IEnumerable<GZipEntry> GetEntries(Stream stream)
protected override IAsyncEnumerable<GZipEntry> GetEntries(Stream stream)
{
return GZipEntry.GetEntries(stream, Options);
}

View File

@@ -1,10 +1,12 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
namespace SharpCompress.Readers
{
public interface IReader : IDisposable
public interface IReader : IAsyncDisposable
{
event EventHandler<ReaderExtractionEventArgs<IEntry>> EntryExtractionProgress;
@@ -13,13 +15,13 @@ namespace SharpCompress.Readers
ArchiveType ArchiveType { get; }
IEntry Entry { get; }
IEntry? Entry { get; }
/// <summary>
/// Decompresses the current entry to the stream. This cannot be called twice for the current entry.
/// </summary>
/// <param name="writableStream"></param>
void WriteEntryTo(Stream writableStream);
ValueTask WriteEntryToAsync(Stream writableStream, CancellationToken cancellationToken = default);
bool Cancelled { get; }
void Cancel();
@@ -28,7 +30,7 @@ namespace SharpCompress.Readers
/// Moves to the next entry by reading more data from the underlying stream. This skips if data has not been read.
/// </summary>
/// <returns></returns>
bool MoveToNextEntry();
ValueTask<bool> MoveToNextEntry();
/// <summary>
/// Opens the current entry as a stream that will decompress as it is read.

View File

@@ -1,63 +1,73 @@
using System.IO;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
namespace SharpCompress.Readers
{
public static class IReaderExtensions
{
public static void WriteEntryTo(this IReader reader, string filePath)
public static async ValueTask WriteEntryToAsync(this IReader reader, string filePath)
{
using (Stream stream = File.Open(filePath, FileMode.Create, FileAccess.Write))
{
reader.WriteEntryTo(stream);
}
await using Stream stream = File.Open(filePath, FileMode.Create, FileAccess.Write);
await reader.WriteEntryToAsync(stream);
}
public static void WriteEntryTo(this IReader reader, FileInfo filePath)
public static async ValueTask WriteEntryTo(this IReader reader, FileInfo filePath)
{
using (Stream stream = filePath.Open(FileMode.Create))
{
reader.WriteEntryTo(stream);
}
await using Stream stream = filePath.Open(FileMode.Create);
await reader.WriteEntryToAsync(stream);
}
/// <summary>
/// Extract all remaining unread entries to specific directory, retaining filename
/// </summary>
public static void WriteAllToDirectory(this IReader reader, string destinationDirectory,
public static async ValueTask WriteAllToDirectoryAsync(this IReader reader, string destinationDirectory,
ExtractionOptions? options = null)
{
while (reader.MoveToNextEntry())
while (await reader.MoveToNextEntry())
{
reader.WriteEntryToDirectory(destinationDirectory, options);
await reader.WriteEntryToDirectoryAsync(destinationDirectory, options);
}
}
/// <summary>
/// Extract to specific directory, retaining filename
/// </summary>
public static void WriteEntryToDirectory(this IReader reader, string destinationDirectory,
ExtractionOptions? options = null)
public static ValueTask WriteEntryToDirectoryAsync(this IReader reader, string destinationDirectory,
ExtractionOptions? options = null,
CancellationToken cancellationToken = default)
{
ExtractionMethods.WriteEntryToDirectory(reader.Entry, destinationDirectory, options,
reader.WriteEntryToFile);
if (reader.Entry is null)
{
throw new ArgumentException("Entry is null");
}
return ExtractionMethods.WriteEntryToDirectoryAsync(reader.Entry, destinationDirectory, options,
async (x, o, ct) =>
{
await reader.WriteEntryToFileAsync(x, o, ct);
}, cancellationToken);
}
/// <summary>
/// Extract to specific file
/// </summary>
public static void WriteEntryToFile(this IReader reader,
public static async ValueTask WriteEntryToFileAsync(this IReader reader,
string destinationFileName,
ExtractionOptions? options = null)
ExtractionOptions? options = null,
CancellationToken cancellationToken = default)
{
ExtractionMethods.WriteEntryToFile(reader.Entry, destinationFileName, options,
(x, fm) =>
if (reader.Entry is null)
{
throw new ArgumentException("Entry is null");
}
await ExtractionMethods.WriteEntryToFileAsync(reader.Entry, destinationFileName, options,
async (x, fm, ct) =>
{
using (FileStream fs = File.Open(destinationFileName, fm))
{
reader.WriteEntryTo(fs);
}
});
await using FileStream fs = File.Open(x, fm);
await reader.WriteEntryToAsync(fs, ct);
}, cancellationToken);
}
}
}

View File

@@ -35,9 +35,9 @@ namespace SharpCompress.Readers.Zip
#endregion Open
protected override IEnumerable<ZipEntry> GetEntries(Stream stream)
protected override async IAsyncEnumerable<ZipEntry> GetEntries(Stream stream)
{
foreach (ZipHeader h in _headerFactory.ReadStreamHeader(stream))
await foreach (ZipHeader h in _headerFactory.ReadStreamHeader(stream))
{
if (h != null)
{

View File

@@ -32,6 +32,30 @@
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.1' ">
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Archives\SevenZip\**" />
<Compile Remove="Archives\Rar\**" />
<Compile Remove="Archives\Tar\**" />
<Compile Remove="Readers\Rar\**" />
<Compile Remove="Readers\Tar\**" />
<Compile Remove="Writers\Tar\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="Archives\SevenZip\**" />
<EmbeddedResource Remove="Archives\Rar\**" />
<EmbeddedResource Remove="Archives\Tar\**" />
<EmbeddedResource Remove="Readers\Rar\**" />
<EmbeddedResource Remove="Readers\Tar\**" />
<EmbeddedResource Remove="Writers\Tar\**" />
</ItemGroup>
<ItemGroup>
<None Remove="Archives\SevenZip\**" />
<None Remove="Archives\Rar\**" />
<None Remove="Archives\Tar\**" />
<None Remove="Readers\Rar\**" />
<None Remove="Readers\Tar\**" />
<None Remove="Writers\Tar\**" />
</ItemGroup>
</Project>

View File

@@ -2,6 +2,7 @@ using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Readers;
@@ -231,20 +232,20 @@ namespace SharpCompress
return sTime.AddSeconds(unixtime);
}
public static async Task<long> TransferToAsync(this Stream source, Stream destination)
public static async Task<long> TransferToAsync(this Stream source, Stream destination, CancellationToken cancellationToken)
{
using var buffer = MemoryPool<byte>.Shared.Rent(81920);
long total = 0;
while (true)
{
int bytesRead = await source.ReadAsync(buffer.Memory);
int bytesRead = await source.ReadAsync(buffer.Memory, cancellationToken);
if (bytesRead == 0)
{
break;
}
total += bytesRead;
await destination.WriteAsync(buffer.Memory);
await destination.WriteAsync(buffer.Memory, cancellationToken);
}
return total;
}
@@ -255,7 +256,8 @@ namespace SharpCompress
try
{
long total = 0;
while (ReadTransferBlock(source, array, out int count))
var count = 0;
while ((count = source.Read(array, 0, array.Length)) != 0)
{
total += count;
destination.Write(array, 0, count);
@@ -268,17 +270,18 @@ namespace SharpCompress
}
}
public static long TransferTo(this Stream source, Stream destination, Common.Entry entry, IReaderExtractionListener readerExtractionListener)
public static async ValueTask<long> TransferToAsync(this Stream source, Stream destination, Common.Entry entry, IReaderExtractionListener readerExtractionListener, CancellationToken cancellationToken)
{
byte[] array = GetTransferByteArray();
try
{
var iterations = 0;
long total = 0;
while (ReadTransferBlock(source, array, out int count))
var count = 0;
while ((count = await source.ReadAsync(array, 0, array.Length, cancellationToken)) != 0)
{
total += count;
destination.Write(array, 0, count);
await destination.WriteAsync(array, 0, count, cancellationToken);
iterations++;
readerExtractionListener.FireEntryExtractionProgress(entry, total, iterations);
}
@@ -290,11 +293,6 @@ namespace SharpCompress
}
}
private static bool ReadTransferBlock(Stream source, byte[] array, out int count)
{
return (count = source.Read(array, 0, array.Length)) != 0;
}
private static byte[] GetTransferByteArray()
{
return ArrayPool<byte>.Shared.Rent(81920);

View File

@@ -1,5 +1,7 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Compressors;
using SharpCompress.Compressors.Deflate;
@@ -18,22 +20,18 @@ namespace SharpCompress.Writers.GZip
{
destination = new NonDisposingStream(destination);
}
InitalizeStream(new GZipStream(destination, CompressionMode.Compress,
InitializeStream(new GZipStream(destination, CompressionMode.Compress,
options?.CompressionLevel ?? CompressionLevel.Default,
WriterOptions.ArchiveEncoding.GetEncoding()));
}
protected override void Dispose(bool isDisposing)
protected override ValueTask DisposeAsyncCore()
{
if (isDisposing)
{
//dispose here to finish the GZip, GZip won't close the underlying stream
OutputStream.Dispose();
}
base.Dispose(isDisposing);
//dispose here to finish the GZip, GZip won't close the underlying stream
return OutputStream.DisposeAsync();
}
public override void Write(string filename, Stream source, DateTime? modificationTime)
public override async Task WriteAsync(string filename, Stream source, DateTime? modificationTime, CancellationToken cancellationToken)
{
if (_wroteToStream)
{
@@ -42,7 +40,7 @@ namespace SharpCompress.Writers.GZip
GZipStream stream = (GZipStream)OutputStream;
stream.FileName = filename;
stream.LastModified = modificationTime;
source.TransferTo(stream);
await source.TransferToAsync(stream);
_wroteToStream = true;
}
}

View File

@@ -2,17 +2,19 @@
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace SharpCompress.Writers
{
public static class IWriterExtensions
{
public static void Write(this IWriter writer, string entryPath, Stream source)
public static Task WriteAsync(this IWriter writer, string entryPath, Stream source, CancellationToken cancellationToken = default)
{
writer.Write(entryPath, source, null);
return writer.WriteAsync(entryPath, source, null, cancellationToken);
}
public static void Write(this IWriter writer, string entryPath, FileInfo source)
public static async Task WriteAsync(this IWriter writer, string entryPath, FileInfo source, CancellationToken cancellationToken = default)
{
if (!source.Exists)
{
@@ -20,25 +22,25 @@ namespace SharpCompress.Writers
}
using (var stream = source.OpenRead())
{
writer.Write(entryPath, stream, source.LastWriteTime);
await writer.WriteAsync(entryPath, stream, source.LastWriteTime, cancellationToken);
}
}
public static void Write(this IWriter writer, string entryPath, string source)
public static Task WriteAsync(this IWriter writer, string entryPath, string source, CancellationToken cancellationToken = default)
{
writer.Write(entryPath, new FileInfo(source));
return writer.WriteAsync(entryPath, new FileInfo(source), cancellationToken);
}
public static void WriteAll(this IWriter writer, string directory, string searchPattern = "*", SearchOption option = SearchOption.TopDirectoryOnly)
public static Task WriteAllAsync(this IWriter writer, string directory, string searchPattern = "*", SearchOption option = SearchOption.TopDirectoryOnly, CancellationToken cancellationToken = default)
{
writer.WriteAll(directory, searchPattern, null, option);
return writer.WriteAllAsync(directory, searchPattern, null, option, cancellationToken);
}
public static void WriteAll(this IWriter writer,
string directory,
string searchPattern = "*",
Expression<Func<string, bool>>? fileSearchFunc = null,
SearchOption option = SearchOption.TopDirectoryOnly)
public static async Task WriteAllAsync(this IWriter writer,
string directory,
string searchPattern = "*",
Expression<Func<string, bool>>? fileSearchFunc = null,
SearchOption option = SearchOption.TopDirectoryOnly, CancellationToken cancellationToken = default)
{
if (!Directory.Exists(directory))
{
@@ -51,7 +53,7 @@ namespace SharpCompress.Writers
}
foreach (var file in Directory.EnumerateFiles(directory, searchPattern, option).Where(fileSearchFunc.Compile()))
{
writer.Write(file.Substring(directory.Length), file);
await writer.WriteAsync(file.Substring(directory.Length), file, cancellationToken);
}
}
}

View File

@@ -1,8 +1,11 @@
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Common.Zip;
using SharpCompress.Common.Zip.Headers;
@@ -42,7 +45,7 @@ namespace SharpCompress.Writers.Zip
{
destination = new NonDisposingStream(destination);
}
InitalizeStream(destination);
InitializeStream(destination);
}
private PpmdProperties PpmdProperties
@@ -53,18 +56,15 @@ namespace SharpCompress.Writers.Zip
}
}
protected override void Dispose(bool isDisposing)
protected override async ValueTask DisposeAsyncCore()
{
if (isDisposing)
ulong size = 0;
foreach (ZipCentralDirectoryEntry entry in entries)
{
ulong size = 0;
foreach (ZipCentralDirectoryEntry entry in entries)
{
size += entry.Write(OutputStream);
}
WriteEndRecord(size);
size += entry.Write(OutputStream);
}
base.Dispose(isDisposing);
await WriteEndRecordAsync(size);
await base.DisposeAsyncCore();
}
private static ZipCompressionMethod ToZipCompressionMethod(CompressionType compressionType)
@@ -96,23 +96,21 @@ namespace SharpCompress.Writers.Zip
}
}
public override void Write(string entryPath, Stream source, DateTime? modificationTime)
public override Task WriteAsync(string filename, Stream source, DateTime? modificationTime, CancellationToken cancellationToken)
{
Write(entryPath, source, new ZipWriterEntryOptions()
{
ModificationDateTime = modificationTime
});
return WriteAsync(filename, source, new ZipWriterEntryOptions()
{
ModificationDateTime = modificationTime
});
}
public void Write(string entryPath, Stream source, ZipWriterEntryOptions zipWriterEntryOptions)
public async Task WriteAsync(string entryPath, Stream source, ZipWriterEntryOptions zipWriterEntryOptions)
{
using (Stream output = WriteToStream(entryPath, zipWriterEntryOptions))
{
source.TransferTo(output);
}
await using Stream output = await WriteToStreamAsync(entryPath, zipWriterEntryOptions);
await source.TransferToAsync(output);
}
public Stream WriteToStream(string entryPath, ZipWriterEntryOptions options)
public async Task<Stream> WriteToStreamAsync(string entryPath, ZipWriterEntryOptions options)
{
var compression = ToZipCompressionMethod(options.CompressionType ?? compressionType);
@@ -132,7 +130,7 @@ namespace SharpCompress.Writers.Zip
useZip64 = options.EnableZip64.Value;
}
var headersize = (uint)WriteHeader(entryPath, options, entry, useZip64);
var headersize = (uint)(await WriteHeaderAsync(entryPath, options, entry, useZip64));
streamPosition += headersize;
return new ZipWritingStream(this, OutputStream, entry, compression,
options.DeflateCompressionLevel ?? compressionLevel);
@@ -151,7 +149,7 @@ namespace SharpCompress.Writers.Zip
return filename.Trim('/');
}
private int WriteHeader(string filename, ZipWriterEntryOptions zipWriterEntryOptions, ZipCentralDirectoryEntry entry, bool useZip64)
private async Task<int> WriteHeaderAsync(string filename, ZipWriterEntryOptions zipWriterEntryOptions, ZipCentralDirectoryEntry entry, bool useZip64)
{
// We err on the side of caution until the zip specification clarifies how to support this
if (!OutputStream.CanSeek && useZip64)
@@ -163,23 +161,32 @@ namespace SharpCompress.Writers.Zip
byte[] encodedFilename = WriterOptions.ArchiveEncoding.Encode(filename);
// TODO: Use stackalloc when we exclusively support netstandard2.1 or higher
byte[] intBuf = new byte[4];
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, ZipHeaderFactory.ENTRY_HEADER_BYTES);
OutputStream.Write(intBuf, 0, 4);
using var intBuf = MemoryPool<byte>.Shared.Rent(4);
BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Memory.Span, ZipHeaderFactory.ENTRY_HEADER_BYTES);
await OutputStream.WriteAsync(intBuf.Memory);
if (explicitZipCompressionInfo == ZipCompressionMethod.Deflate)
{
if (OutputStream.CanSeek && useZip64)
{
OutputStream.Write(stackalloc byte[] { 45, 0 }); //smallest allowed version for zip64
using var buf1 = MemoryPool<byte>.Shared.Rent(2);
buf1.Memory.Span[0] = 45;
buf1.Memory.Span[1] = 0;
await OutputStream.WriteAsync(buf1.Memory); //smallest allowed version for zip64
}
else
{
OutputStream.Write(stackalloc byte[] { 20, 0 }); //older version which is more compatible
using var buf1 = MemoryPool<byte>.Shared.Rent(2);
buf1.Memory.Span[0] = 20;
buf1.Memory.Span[1] = 0;
await OutputStream.WriteAsync(buf1.Memory); //older version which is more compatible
}
}
else
{
OutputStream.Write(stackalloc byte[] { 63, 0 }); //version says we used PPMd or LZMA
using var buf1 = MemoryPool<byte>.Shared.Rent(2);
buf1.Memory.Span[0] = 63;
buf1.Memory.Span[1] = 0;
await OutputStream.WriteAsync(buf1.Memory); //version says we used PPMd or LZMA
}
HeaderFlags flags = Equals(WriterOptions.ArchiveEncoding.GetEncoding(), Encoding.UTF8) ? HeaderFlags.Efs : 0;
if (!OutputStream.CanSeek)
@@ -192,19 +199,21 @@ namespace SharpCompress.Writers.Zip
}
}
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)flags);
OutputStream.Write(intBuf, 0, 2);
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)explicitZipCompressionInfo);
OutputStream.Write(intBuf, 0, 2); // zipping method
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, zipWriterEntryOptions.ModificationDateTime.DateTimeToDosTime());
OutputStream.Write(intBuf, 0, 4);
BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Memory.Span, (ushort)flags);
await OutputStream.WriteAsync(intBuf.Memory.Slice(0,2));
BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Memory.Span, (ushort)explicitZipCompressionInfo);
await OutputStream.WriteAsync(intBuf.Memory.Slice(0,2)); // zipping method
BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Memory.Span, zipWriterEntryOptions.ModificationDateTime.DateTimeToDosTime());
await OutputStream.WriteAsync(intBuf.Memory);
// zipping date and time
OutputStream.Write(stackalloc byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 });
using var buf2 = MemoryPool<byte>.Shared.Rent(12);
buf2.Memory.Span.Clear();
await OutputStream.WriteAsync(buf2.Memory);
// unused CRC, un/compressed size, updated later
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)encodedFilename.Length);
OutputStream.Write(intBuf, 0, 2); // filename length
BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Memory.Span, (ushort)encodedFilename.Length);
await OutputStream.WriteAsync(intBuf.Memory.Slice(0,2));// filename length
var extralength = 0;
if (OutputStream.CanSeek && useZip64)
@@ -212,31 +221,33 @@ namespace SharpCompress.Writers.Zip
extralength = 2 + 2 + 8 + 8;
}
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)extralength);
OutputStream.Write(intBuf, 0, 2); // extra length
OutputStream.Write(encodedFilename, 0, encodedFilename.Length);
BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Memory.Span, (ushort)extralength);
await OutputStream.WriteAsync(intBuf.Memory.Slice(0,2));// extra length
await OutputStream.WriteAsync(encodedFilename, 0, encodedFilename.Length);
if (extralength != 0)
{
OutputStream.Write(new byte[extralength], 0, extralength); // reserve space for zip64 data
using var buf3 = MemoryPool<byte>.Shared.Rent(extralength);
buf2.Memory.Span.Clear();
await OutputStream.WriteAsync(buf3.Memory); // reserve space for zip64 data
entry.Zip64HeaderOffset = (ushort)(6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length);
}
return 6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length + extralength;
}
private void WriteFooter(uint crc, uint compressed, uint uncompressed)
private async Task WriteFooterAsync(uint crc, uint compressed, uint uncompressed)
{
byte[] intBuf = new byte[4];
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, crc);
OutputStream.Write(intBuf, 0, 4);
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, compressed);
OutputStream.Write(intBuf, 0, 4);
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, uncompressed);
OutputStream.Write(intBuf, 0, 4);
using var intBuf = MemoryPool<byte>.Shared.Rent(4);
BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Memory.Span, crc);
await OutputStream.WriteAsync(intBuf.Memory);
BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Memory.Span, compressed);
await OutputStream.WriteAsync(intBuf.Memory);
BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Memory.Span, uncompressed);
await OutputStream.WriteAsync(intBuf.Memory);
}
private void WriteEndRecord(ulong size)
private async Task WriteEndRecordAsync(ulong size)
{
var zip64 = isZip64 || entries.Count > ushort.MaxValue || streamPosition >= uint.MaxValue || size >= uint.MaxValue;
@@ -244,66 +255,82 @@ namespace SharpCompress.Writers.Zip
var sizevalue = size >= uint.MaxValue ? uint.MaxValue : (uint)size;
var streampositionvalue = streamPosition >= uint.MaxValue ? uint.MaxValue : (uint)streamPosition;
byte[] intBuf = new byte[8];
using var intBuf = MemoryPool<byte>.Shared.Rent(8);
if (zip64)
{
var recordlen = 2 + 2 + 4 + 4 + 8 + 8 + 8 + 8;
// Write zip64 end of central directory record
OutputStream.Write(stackalloc byte[] { 80, 75, 6, 6 });
var s = intBuf.Memory.Slice(0, 4);
s.Span[0] = 80;
s.Span[1] = 75;
s.Span[2] = 6;
s.Span[3] = 6;
await OutputStream.WriteAsync(s);
BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)recordlen);
OutputStream.Write(intBuf, 0, 8); // Size of zip64 end of central directory record
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0);
OutputStream.Write(intBuf, 0, 2); // Made by
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 45);
OutputStream.Write(intBuf, 0, 2); // Version needed
BinaryPrimitives.WriteUInt64LittleEndian(intBuf.Memory.Span, (ulong)recordlen);
await OutputStream.WriteAsync(intBuf.Memory);// Size of zip64 end of central directory record
BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Memory.Span, 0);
await OutputStream.WriteAsync(intBuf.Memory.Slice(0, 2)); // Made by
BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Memory.Span, 45);
await OutputStream.WriteAsync(intBuf.Memory.Slice(0, 2)); // Version needed
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 0);
OutputStream.Write(intBuf, 0, 4); // Disk number
OutputStream.Write(intBuf, 0, 4); // Central dir disk
intBuf.Memory.Span.Clear();
await OutputStream.WriteAsync(intBuf.Memory.Slice(0, 4)); // Disk number
await OutputStream.WriteAsync(intBuf.Memory.Slice(0, 4)); // Central dir disk
// TODO: entries.Count is int, so max 2^31 files
BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)entries.Count);
OutputStream.Write(intBuf, 0, 8); // Entries in this disk
OutputStream.Write(intBuf, 0, 8); // Total entries
BinaryPrimitives.WriteUInt64LittleEndian(intBuf, size);
OutputStream.Write(intBuf, 0, 8); // Central Directory size
BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)streamPosition);
OutputStream.Write(intBuf, 0, 8); // Disk offset
BinaryPrimitives.WriteUInt64LittleEndian(intBuf.Memory.Span, (ulong)entries.Count);
await OutputStream.WriteAsync(intBuf.Memory); // Entries in this disk
await OutputStream.WriteAsync(intBuf.Memory); // Total entries
BinaryPrimitives.WriteUInt64LittleEndian(intBuf.Memory.Span, size);
await OutputStream.WriteAsync(intBuf.Memory); // Central Directory size
BinaryPrimitives.WriteUInt64LittleEndian(intBuf.Memory.Span, (ulong)streamPosition);
await OutputStream.WriteAsync(intBuf.Memory); // Disk offset
// Write zip64 end of central directory locator
OutputStream.Write(stackalloc byte[] { 80, 75, 6, 7 });
s = intBuf.Memory.Slice(0, 4);
s.Span[0] = 80;
s.Span[1] = 75;
s.Span[2] = 6;
s.Span[3] = 7;
await OutputStream.WriteAsync(s);
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 0);
OutputStream.Write(intBuf, 0, 4); // Entry disk
BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)streamPosition + size);
OutputStream.Write(intBuf, 0, 8); // Offset to the zip64 central directory
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 0);
OutputStream.Write(intBuf, 0, 4); // Number of disks
BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Memory.Span, 0);
await OutputStream.WriteAsync(intBuf.Memory.Slice(0, 4)); // Entry disk
BinaryPrimitives.WriteUInt64LittleEndian(intBuf.Memory.Span, (ulong)streamPosition + size);
await OutputStream.WriteAsync(intBuf.Memory); // Offset to the zip64 central directory
BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Memory.Span, 0);
await OutputStream.WriteAsync(intBuf.Memory.Slice(0, 4)); // Number of disks
streamPosition += recordlen + (4 + 4 + 8 + 4);
streampositionvalue = streamPosition >= uint.MaxValue ? uint.MaxValue : (uint)streampositionvalue;
}
// Write normal end of central directory record
OutputStream.Write(stackalloc byte[] { 80, 75, 5, 6, 0, 0, 0, 0 });
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)entries.Count);
OutputStream.Write(intBuf, 0, 2);
OutputStream.Write(intBuf, 0, 2);
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, sizevalue);
OutputStream.Write(intBuf, 0, 4);
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, streampositionvalue);
OutputStream.Write(intBuf, 0, 4);
intBuf.Memory.Span.Clear();
var x = intBuf.Memory.Slice(0, 4);
x.Span[0] = 80;
x.Span[1] = 75;
x.Span[2] = 5;
x.Span[3] = 6;
await OutputStream.WriteAsync(intBuf.Memory);
BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Memory.Span, (ushort)entries.Count);
await OutputStream.WriteAsync(intBuf.Memory.Slice(0, 2));
await OutputStream.WriteAsync(intBuf.Memory.Slice(0, 2));//TODO: this is twice?
BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Memory.Span, sizevalue);
await OutputStream.WriteAsync(intBuf.Memory.Slice(0, 4));
BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Memory.Span, streampositionvalue);
await OutputStream.WriteAsync(intBuf.Memory.Slice(0, 4));
byte[] encodedComment = WriterOptions.ArchiveEncoding.Encode(zipComment);
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)encodedComment.Length);
OutputStream.Write(intBuf, 0, 2);
OutputStream.Write(encodedComment, 0, encodedComment.Length);
BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Memory.Span, (ushort)encodedComment.Length);
await OutputStream.WriteAsync(intBuf.Memory.Slice(0, 2));
await OutputStream.WriteAsync(encodedComment.AsMemory());
}
#region Nested type: ZipWritingStream
internal class ZipWritingStream : Stream
private class ZipWritingStream : Stream
{
private readonly CRC32 crc = new CRC32();
private readonly ZipCentralDirectoryEntry entry;
@@ -383,7 +410,7 @@ namespace SharpCompress.Writers.Zip
}
}
protected override void Dispose(bool disposing)
public override async ValueTask DisposeAsync()
{
if (isDisposed)
{
@@ -392,95 +419,92 @@ namespace SharpCompress.Writers.Zip
isDisposed = true;
base.Dispose(disposing);
if (disposing)
await base.DisposeAsync();
await writeStream.DisposeAsync();
if (limitsExceeded)
{
writeStream.Dispose();
if (limitsExceeded)
{
// We have written invalid data into the archive,
// so we destroy it now, instead of allowing the user to continue
// with a defunct archive
originalStream.Dispose();
return;
}
entry.Crc = (uint)crc.Crc32Result;
entry.Compressed = counting!.Count;
entry.Decompressed = decompressed;
var zip64 = entry.Compressed >= uint.MaxValue || entry.Decompressed >= uint.MaxValue;
var compressedvalue = zip64 ? uint.MaxValue : (uint)counting.Count;
var decompressedvalue = zip64 ? uint.MaxValue : (uint)entry.Decompressed;
if (originalStream.CanSeek)
{
originalStream.Position = (long)(entry.HeaderOffset + 6);
originalStream.WriteByte(0);
if (counting.Count == 0 && entry.Decompressed == 0)
{
// set compression to STORED for zero byte files (no compression data)
originalStream.Position = (long)(entry.HeaderOffset + 8);
originalStream.WriteByte(0);
originalStream.WriteByte(0);
}
originalStream.Position = (long)(entry.HeaderOffset + 14);
writer.WriteFooter(entry.Crc, compressedvalue, decompressedvalue);
// Ideally, we should not throw from Dispose()
// We should not get here as the Write call checks the limits
if (zip64 && entry.Zip64HeaderOffset == 0)
{
throw new NotSupportedException("Attempted to write a stream that is larger than 4GiB without setting the zip64 option");
}
// If we have pre-allocated space for zip64 data,
// fill it out, even if it is not required
if (entry.Zip64HeaderOffset != 0)
{
originalStream.Position = (long)(entry.HeaderOffset + entry.Zip64HeaderOffset);
byte[] intBuf = new byte[8];
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0x0001);
originalStream.Write(intBuf, 0, 2);
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 8 + 8);
originalStream.Write(intBuf, 0, 2);
BinaryPrimitives.WriteUInt64LittleEndian(intBuf, entry.Decompressed);
originalStream.Write(intBuf, 0, 8);
BinaryPrimitives.WriteUInt64LittleEndian(intBuf, entry.Compressed);
originalStream.Write(intBuf, 0, 8);
}
originalStream.Position = writer.streamPosition + (long)entry.Compressed;
writer.streamPosition += (long)entry.Compressed;
}
else
{
// We have a streaming archive, so we should add a post-data-descriptor,
// but we cannot as it does not hold the zip64 values
// Throwing an exception until the zip specification is clarified
// Ideally, we should not throw from Dispose()
// We should not get here as the Write call checks the limits
if (zip64)
{
throw new NotSupportedException("Streams larger than 4GiB are not supported for non-seekable streams");
}
byte[] intBuf = new byte[4];
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, ZipHeaderFactory.POST_DATA_DESCRIPTOR);
originalStream.Write(intBuf, 0, 4);
writer.WriteFooter(entry.Crc,
compressedvalue,
decompressedvalue);
writer.streamPosition += (long)entry.Compressed + 16;
}
writer.entries.Add(entry);
// We have written invalid data into the archive,
// so we destroy it now, instead of allowing the user to continue
// with a defunct archive
await originalStream.DisposeAsync();
return;
}
entry.Crc = (uint)crc.Crc32Result;
entry.Compressed = counting!.Count;
entry.Decompressed = decompressed;
var zip64 = entry.Compressed >= uint.MaxValue || entry.Decompressed >= uint.MaxValue;
var compressedvalue = zip64 ? uint.MaxValue : (uint)counting.Count;
var decompressedvalue = zip64 ? uint.MaxValue : (uint)entry.Decompressed;
if (originalStream.CanSeek)
{
originalStream.Position = (long)(entry.HeaderOffset + 6);
originalStream.WriteByte(0);
if (counting.Count == 0 && entry.Decompressed == 0)
{
// set compression to STORED for zero byte files (no compression data)
originalStream.Position = (long)(entry.HeaderOffset + 8);
originalStream.WriteByte(0);
originalStream.WriteByte(0);
}
originalStream.Position = (long)(entry.HeaderOffset + 14);
await writer.WriteFooterAsync(entry.Crc, compressedvalue, decompressedvalue);
// Ideally, we should not throw from Dispose()
// We should not get here as the Write call checks the limits
if (zip64 && entry.Zip64HeaderOffset == 0)
{
throw new NotSupportedException("Attempted to write a stream that is larger than 4GiB without setting the zip64 option");
}
// If we have pre-allocated space for zip64 data,
// fill it out, even if it is not required
if (entry.Zip64HeaderOffset != 0)
{
originalStream.Position = (long)(entry.HeaderOffset + entry.Zip64HeaderOffset);
byte[] intBuf = new byte[8];
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0x0001);
await originalStream.WriteAsync(intBuf, 0, 2);
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 8 + 8);
await originalStream.WriteAsync(intBuf, 0, 2);
BinaryPrimitives.WriteUInt64LittleEndian(intBuf, entry.Decompressed);
await originalStream.WriteAsync(intBuf, 0, 8);
BinaryPrimitives.WriteUInt64LittleEndian(intBuf, entry.Compressed);
await originalStream.WriteAsync(intBuf, 0, 8);
}
originalStream.Position = writer.streamPosition + (long)entry.Compressed;
writer.streamPosition += (long)entry.Compressed;
}
else
{
// We have a streaming archive, so we should add a post-data-descriptor,
// but we cannot as it does not hold the zip64 values
// Throwing an exception until the zip specification is clarified
// Ideally, we should not throw from Dispose()
// We should not get here as the Write call checks the limits
if (zip64)
{
throw new NotSupportedException("Streams larger than 4GiB are not supported for non-seekable streams");
}
using var intBuf = MemoryPool<byte>.Shared.Rent(4);
BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Memory.Span, ZipHeaderFactory.POST_DATA_DESCRIPTOR);
await originalStream.WriteAsync(intBuf.Memory);
await writer.WriteFooterAsync(entry.Crc,
compressedvalue,
decompressedvalue);
writer.streamPosition += (long)entry.Compressed + 16;
}
writer.entries.Add(entry);
}
public override void Flush()
@@ -488,6 +512,11 @@ namespace SharpCompress.Writers.Zip
writeStream.Flush();
}
public override Task FlushAsync(CancellationToken cancellationToken)
{
return writeStream.FlushAsync(cancellationToken);
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
@@ -504,6 +533,11 @@ namespace SharpCompress.Writers.Zip
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
// We check the limits first, because we can keep the archive consistent
// if we can prevent the writes from happening
@@ -518,7 +552,7 @@ namespace SharpCompress.Writers.Zip
decompressed += (uint)count;
crc.SlurpBlock(buffer, offset, count);
writeStream.Write(buffer, offset, count);
await writeStream.WriteAsync(buffer, offset, count, cancellationToken);
if (entry.Zip64HeaderOffset == 0)
{

View File

@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using SharpCompress.Archives;
using SharpCompress.Archives.GZip;
using Xunit;
@@ -56,14 +57,14 @@ namespace SharpCompress.Test.GZip
[Fact]
public void GZip_Archive_NoAdd()
public async Task GZip_Archive_NoAdd()
{
string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg");
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")))
await using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")))
using (var archive = GZipArchive.Open(stream))
{
Assert.Throws<InvalidOperationException>(() => archive.AddEntry("jpg\\test.jpg", jpg));
archive.SaveTo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"));
await archive.SaveToAsync(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"));
}
}

View File

@@ -21,7 +21,7 @@ namespace SharpCompress.Test.GZip
using (Stream stream = File.Open(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), FileMode.OpenOrCreate, FileAccess.Write))
await using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.GZip))
{
writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
await writer.WriteAsync("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
}
CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"),
Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"));
@@ -33,7 +33,7 @@ namespace SharpCompress.Test.GZip
using (Stream stream = File.Open(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), FileMode.OpenOrCreate, FileAccess.Write))
await using (var writer = new GZipWriter(stream))
{
writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
await writer.WriteAsync("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
}
CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"),
Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"));
@@ -58,7 +58,7 @@ namespace SharpCompress.Test.GZip
await using (var writer = new GZipWriter(stream))
{
var path = Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar");
writer.Write(path, path); //covers issue #532
await writer.WriteAsync(path, path); //covers issue #532
}
CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"),
Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"));

View File

@@ -21,4 +21,19 @@
<PackageReference Include="Xunit.SkippableFact" Version="1.4.13" />
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Rar\**" />
<Compile Remove="SevenZip\**" />
<Compile Remove="Tar\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="Rar\**" />
<EmbeddedResource Remove="SevenZip\**" />
<EmbeddedResource Remove="Tar\**" />
</ItemGroup>
<ItemGroup>
<None Remove="Rar\**" />
<None Remove="SevenZip\**" />
<None Remove="Tar\**" />
</ItemGroup>
</Project>

View File

@@ -125,7 +125,7 @@ namespace SharpCompress.Test.Tar
}
[Fact]
public async Task Tar_UstarArchivePathReadLongName()
public void Tar_UstarArchivePathReadLongName()
{
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "ustar with long names.tar");
using var archive = TarArchive.Open(unmodified);
@@ -154,7 +154,7 @@ namespace SharpCompress.Test.Tar
{
Default = Encoding.GetEncoding(866)
};
archive.SaveTo(scratchPath, twopt);
await archive.SaveToAsync(scratchPath, twopt);
}
CompareArchivesByPath(unmodified, scratchPath);
}
@@ -169,7 +169,7 @@ namespace SharpCompress.Test.Tar
using (var archive = TarArchive.Open(unmodified))
{
archive.AddEntry("jpg\\test.jpg", jpg);
archive.SaveTo(scratchPath, CompressionType.None);
await archive.SaveToAsync(scratchPath, CompressionType.None);
}
CompareArchivesByPath(modified, scratchPath);
}
@@ -185,13 +185,13 @@ namespace SharpCompress.Test.Tar
{
var entry = archive.Entries.Single(x => x.Key.EndsWith("jpg"));
archive.RemoveEntry(entry);
archive.SaveTo(scratchPath, CompressionType.None);
await archive.SaveToAsync(scratchPath, CompressionType.None);
}
CompareArchivesByPath(modified, scratchPath);
}
[Fact]
public async Task Tar_Containing_Rar_Archive()
public void Tar_Containing_Rar_Archive()
{
string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsRar.tar");
using Stream stream = File.OpenRead(archiveFullPath);
@@ -200,7 +200,7 @@ namespace SharpCompress.Test.Tar
}
[Fact]
public async Task Tar_Empty_Archive()
public void Tar_Empty_Archive()
{
string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.Empty.tar");
using Stream stream = File.OpenRead(archiveFullPath);
@@ -252,9 +252,9 @@ namespace SharpCompress.Test.Tar
await using (var tarWriter = new TarWriter(memoryStream, tarWriterOptions))
using (var testFileStream = new MemoryStream(testBytes))
{
tarWriter.Write("test1.txt", testFileStream);
await tarWriter.WriteAsync("test1.txt", testFileStream);
testFileStream.Position = 0;
tarWriter.Write("test2.txt", testFileStream);
await tarWriter.WriteAsync("test2.txt", testFileStream);
}
memoryStream.Position = 0;

View File

@@ -30,7 +30,7 @@ namespace SharpCompress.Test
await using (var writer = WriterFactory.Open(stream, type, writerOptions))
{
writer.WriteAll(ORIGINAL_FILES_PATH, "*", SearchOption.AllDirectories);
await writer.WriteAllAsync(ORIGINAL_FILES_PATH, "*", SearchOption.AllDirectories);
}
}
CompareArchivesByPath(Path.Combine(SCRATCH2_FILES_PATH, archive),

View File

@@ -24,47 +24,47 @@ namespace SharpCompress.Test.Zip
private const long FOUR_GB_LIMIT = ((long)uint.MaxValue) + 1;
[Trait("format", "zip64")]
public void Zip64_Single_Large_File()
public async Task Zip64_Single_Large_File()
{
// One single file, requires zip64
RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: true, forward_only: false);
await RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: true, forward_only: false);
}
[Trait("format", "zip64")]
public void Zip64_Two_Large_Files()
public async Task Zip64_Two_Large_Files()
{
// One single file, requires zip64
RunSingleTest(2, FOUR_GB_LIMIT, set_zip64: true, forward_only: false);
await RunSingleTest(2, FOUR_GB_LIMIT, set_zip64: true, forward_only: false);
}
[Trait("format", "zip64")]
public void Zip64_Two_Small_files()
public async Task Zip64_Two_Small_files()
{
// Multiple files, does not require zip64
RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: false, forward_only: false);
await RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: false, forward_only: false);
}
[Trait("format", "zip64")]
public void Zip64_Two_Small_files_stream()
public async Task Zip64_Two_Small_files_stream()
{
// Multiple files, does not require zip64, and works with streams
RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: false, forward_only: true);
await RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: false, forward_only: true);
}
[Trait("format", "zip64")]
public void Zip64_Two_Small_Files_Zip64()
public async Task Zip64_Two_Small_Files_Zip64()
{
// Multiple files, use zip64 even though it is not required
RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: true, forward_only: false);
await RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: true, forward_only: false);
}
[Trait("format", "zip64")]
public void Zip64_Single_Large_File_Fail()
public async Task Zip64_Single_Large_File_Fail()
{
try
{
// One single file, should fail
RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: false, forward_only: false);
await RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: false, forward_only: false);
throw new Exception("Test did not fail?");
}
catch (NotSupportedException)
@@ -73,12 +73,12 @@ namespace SharpCompress.Test.Zip
}
[Trait("zip64", "true")]
public void Zip64_Single_Large_File_Zip64_Streaming_Fail()
public async Task Zip64_Single_Large_File_Zip64_Streaming_Fail()
{
try
{
// One single file, should fail (fast) with zip64
RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: true, forward_only: true);
await RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: true, forward_only: true);
throw new Exception("Test did not fail?");
}
catch (NotSupportedException)
@@ -87,12 +87,12 @@ namespace SharpCompress.Test.Zip
}
[Trait("zip64", "true")]
public void Zip64_Single_Large_File_Streaming_Fail()
public async Task Zip64_Single_Large_File_Streaming_Fail()
{
try
{
// One single file, should fail once the write discovers the problem
RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: false, forward_only: true);
await RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: false, forward_only: true);
throw new Exception("Test did not fail?");
}
catch (NotSupportedException)
@@ -100,7 +100,7 @@ namespace SharpCompress.Test.Zip
}
}
public void RunSingleTest(long files, long filesize, bool set_zip64, bool forward_only, long write_chunk_size = 1024 * 1024, string filename = "zip64-test.zip")
public async Task RunSingleTest(long files, long filesize, bool set_zip64, bool forward_only, long write_chunk_size = 1024 * 1024, string filename = "zip64-test.zip")
{
filename = Path.Combine(SCRATCH2_FILES_PATH, filename);
@@ -111,7 +111,7 @@ namespace SharpCompress.Test.Zip
if (!File.Exists(filename))
{
CreateZipArchive(filename, files, filesize, write_chunk_size, set_zip64, forward_only);
await CreateZipArchive(filename, files, filesize, write_chunk_size, set_zip64, forward_only);
}
var resForward = ReadForwardOnly(filename);
@@ -154,13 +154,13 @@ namespace SharpCompress.Test.Zip
for (var i = 0; i < files; i++)
{
using (var str = zipWriter.WriteToStream(i.ToString(), eo))
await using (var str = await zipWriter.WriteToStreamAsync(i.ToString(), eo))
{
var left = filesize;
while (left > 0)
{
var b = (int)Math.Min(left, data.Length);
str.Write(data, 0, b);
await str.WriteAsync(data, 0, b);
left -= b;
}
}

View File

@@ -153,7 +153,7 @@ namespace SharpCompress.Test.Zip
}
[Fact]
public void Zip_Random_Write_Remove()
public async Task Zip_Random_Write_Remove()
{
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip");
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
@@ -167,13 +167,13 @@ namespace SharpCompress.Test.Zip
WriterOptions writerOptions = new ZipWriterOptions(CompressionType.Deflate);
writerOptions.ArchiveEncoding.Default = Encoding.GetEncoding(866);
archive.SaveTo(scratchPath, writerOptions);
await archive.SaveToAsync(scratchPath, writerOptions);
}
CompareArchivesByPath(modified, scratchPath, Encoding.GetEncoding(866));
}
[Fact]
public void Zip_Random_Write_Add()
public async Task Zip_Random_Write_Add()
{
string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg");
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip");
@@ -187,13 +187,13 @@ namespace SharpCompress.Test.Zip
WriterOptions writerOptions = new ZipWriterOptions(CompressionType.Deflate);
writerOptions.ArchiveEncoding.Default = Encoding.GetEncoding(866);
archive.SaveTo(scratchPath, writerOptions);
await archive.SaveToAsync(scratchPath, writerOptions);
}
CompareArchivesByPath(modified, scratchPath, Encoding.GetEncoding(866));
}
[Fact]
public void Zip_Save_Twice()
public async Task Zip_Save_Twice()
{
string scratchPath1 = Path.Combine(SCRATCH_FILES_PATH, "a.zip");
string scratchPath2 = Path.Combine(SCRATCH_FILES_PATH, "b.zip");
@@ -203,8 +203,8 @@ namespace SharpCompress.Test.Zip
string str = "test.txt";
var source = new MemoryStream(Encoding.UTF8.GetBytes(str));
arc.AddEntry("test.txt", source, true, source.Length);
arc.SaveTo(scratchPath1, CompressionType.Deflate);
arc.SaveTo(scratchPath2, CompressionType.Deflate);
await arc.SaveToAsync(scratchPath1, CompressionType.Deflate);
await arc.SaveToAsync(scratchPath2, CompressionType.Deflate);
}
Assert.Equal(new FileInfo(scratchPath1).Length, new FileInfo(scratchPath2).Length);
@@ -238,7 +238,7 @@ namespace SharpCompress.Test.Zip
}
[Fact]
public void Zip_Create_Same_Stream()
public async Task Zip_Create_Same_Stream()
{
string scratchPath1 = Path.Combine(SCRATCH_FILES_PATH, "a.zip");
string scratchPath2 = Path.Combine(SCRATCH_FILES_PATH, "b.zip");
@@ -249,8 +249,8 @@ namespace SharpCompress.Test.Zip
{
arc.AddEntry("1.txt", stream, false, stream.Length);
arc.AddEntry("2.txt", stream, false, stream.Length);
arc.SaveTo(scratchPath1, CompressionType.Deflate);
arc.SaveTo(scratchPath2, CompressionType.Deflate);
await arc.SaveToAsync(scratchPath1, CompressionType.Deflate);
await arc.SaveToAsync(scratchPath2, CompressionType.Deflate);
}
}
@@ -258,7 +258,7 @@ namespace SharpCompress.Test.Zip
}
[Fact]
public void Zip_Create_New()
public async Task Zip_Create_New()
{
foreach (var file in Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories))
{
@@ -285,7 +285,7 @@ namespace SharpCompress.Test.Zip
WriterOptions writerOptions = new ZipWriterOptions(CompressionType.Deflate);
writerOptions.ArchiveEncoding.Default = Encoding.GetEncoding(866);
archive.SaveTo(scratchPath, writerOptions);
await archive.SaveToAsync(scratchPath, writerOptions);
}
CompareArchivesByPath(unmodified, scratchPath, Encoding.GetEncoding(866));
Directory.Delete(SCRATCH_FILES_PATH, true);
@@ -395,7 +395,7 @@ namespace SharpCompress.Test.Zip
}
[Fact]
public void Zip_Random_Entry_Access()
public async Task Zip_Random_Entry_Access()
{
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
@@ -421,8 +421,9 @@ namespace SharpCompress.Test.Zip
if (count2 == count)
{
var s = e.OpenEntryStream();
s.ReadByte(); //Actually access stream
s.Dispose();
byte[] b = new byte[1];
await s.ReadAsync(b, 0, 1); //Actually access stream
await s.DisposeAsync();
break;
}
}
@@ -497,26 +498,26 @@ namespace SharpCompress.Test.Zip
await using (IWriter zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate))
{
zipWriter.Write("foo.txt", new MemoryStream(new byte[0]));
zipWriter.Write("foo2.txt", new MemoryStream(new byte[10]));
await zipWriter.WriteAsync("foo.txt", new MemoryStream(new byte[0]));
await zipWriter.WriteAsync("foo2.txt", new MemoryStream(new byte[10]));
}
stream = new MemoryStream(stream.ToArray());
File.WriteAllBytes(Path.Combine(SCRATCH_FILES_PATH, "foo.zip"), stream.ToArray());
await File.WriteAllBytesAsync(Path.Combine(SCRATCH_FILES_PATH, "foo.zip"), stream.ToArray());
using (var zipArchive = ZipArchive.Open(stream))
{
foreach (var entry in zipArchive.Entries)
{
using (var entryStream = entry.OpenEntryStream())
await using (var entryStream = entry.OpenEntryStream())
{
MemoryStream tempStream = new MemoryStream();
const int bufSize = 0x1000;
byte[] buf = new byte[bufSize];
int bytesRead = 0;
while ((bytesRead = entryStream.Read(buf, 0, bufSize)) > 0)
while ((bytesRead = await entryStream.ReadAsync(buf, 0, bufSize)) > 0)
{
tempStream.Write(buf, 0, bytesRead);
await tempStream.WriteAsync(buf, 0, bytesRead);
}
}
}
@@ -524,13 +525,13 @@ namespace SharpCompress.Test.Zip
}
[Fact]
public void Zip_BadLocalExtra_Read()
public async Task Zip_BadLocalExtra_Read()
{
string zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.badlocalextra.zip");
using (ZipArchive za = ZipArchive.Open(zipPath))
{
var ex = Record.Exception(() =>
var ex = await Record.ExceptionAsync(async () =>
{
var firstEntry = za.Entries.First(x => x.Key == "first.txt");
var buffer = new byte[4096];
@@ -538,7 +539,7 @@ namespace SharpCompress.Test.Zip
using (var memoryStream = new MemoryStream())
using (var firstStream = firstEntry.OpenEntryStream())
{
firstStream.CopyTo(memoryStream);
await firstStream.CopyToAsync(memoryStream);
Assert.Equal(199, memoryStream.Length);
}
});

View File

@@ -279,25 +279,25 @@ namespace SharpCompress.Test.Zip
new Tuple<string, byte[]>("foo2.txt", new byte[10])
};
using (var memory = new MemoryStream())
await using (var memory = new MemoryStream())
{
Stream stream = new TestStream(memory, read: true, write: true, seek: false);
await using (IWriter zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate))
{
zipWriter.Write(expected[0].Item1, new MemoryStream(expected[0].Item2));
zipWriter.Write(expected[1].Item1, new MemoryStream(expected[1].Item2));
await zipWriter.WriteAsync(expected[0].Item1, new MemoryStream(expected[0].Item2));
await zipWriter.WriteAsync(expected[1].Item1, new MemoryStream(expected[1].Item2));
}
stream = new MemoryStream(memory.ToArray());
File.WriteAllBytes(Path.Combine(SCRATCH_FILES_PATH, "foo.zip"), memory.ToArray());
await File.WriteAllBytesAsync(Path.Combine(SCRATCH_FILES_PATH, "foo.zip"), memory.ToArray());
using (IReader zipReader = ZipReader.Open(new NonDisposingStream(stream, true)))
{
var i = 0;
while (zipReader.MoveToNextEntry())
{
using (EntryStream entry = zipReader.OpenEntryStream())
await using (EntryStream entry = zipReader.OpenEntryStream())
{
MemoryStream tempStream = new MemoryStream();
const int bufSize = 0x1000;