mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-25 00:15:15 +00:00
more async await
This commit is contained in:
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user