mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-10-01 11:22:44 +00:00
Merge remote-tracking branch 'origin/master' into adam/add-alternate-compressions
# Conflicts: # src/SharpCompress/Archives/GZip/GZipArchive.Async.cs # src/SharpCompress/Archives/GZip/GZipArchive.cs # src/SharpCompress/Archives/Zip/ZipArchive.Async.cs # src/SharpCompress/Archives/Zip/ZipArchive.cs # src/SharpCompress/Common/GZip/GZipEntry.Async.cs # src/SharpCompress/Common/GZip/GZipEntry.cs # src/SharpCompress/Common/Options/IReaderOptions.cs # src/SharpCompress/Readers/ReaderOptions.cs # src/SharpCompress/Readers/Zip/ZipReader.Async.cs # src/SharpCompress/Readers/Zip/ZipReader.cs # src/SharpCompress/Writers/GZip/GZipWriterOptions.cs
This commit is contained in:
@@ -21,7 +21,7 @@ public abstract partial class AbstractArchive<TEntry, TVolume>
|
||||
IAsyncEnumerable<TVolume> volumes
|
||||
)
|
||||
{
|
||||
foreach (var item in LoadEntries(await volumes.ToListAsync()))
|
||||
foreach (var item in LoadEntries(await volumes.ToListAsync().ConfigureAwait(false)))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
@@ -47,8 +47,8 @@ public abstract partial class AbstractArchive<TEntry, TVolume>
|
||||
|
||||
private async ValueTask EnsureEntriesLoadedAsync()
|
||||
{
|
||||
await _lazyEntriesAsync.EnsureFullyLoaded();
|
||||
await _lazyVolumesAsync.EnsureFullyLoaded();
|
||||
await _lazyEntriesAsync.EnsureFullyLoaded().ConfigureAwait(false);
|
||||
await _lazyVolumesAsync.EnsureFullyLoaded().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async IAsyncEnumerable<IArchiveEntry> EntriesAsyncCast()
|
||||
@@ -73,29 +73,31 @@ public abstract partial class AbstractArchive<TEntry, TVolume>
|
||||
|
||||
public async ValueTask<IAsyncReader> ExtractAllEntriesAsync()
|
||||
{
|
||||
if (!await IsSolidAsync() && Type != ArchiveType.SevenZip)
|
||||
if (!await IsSolidAsync().ConfigureAwait(false) && Type != ArchiveType.SevenZip)
|
||||
{
|
||||
throw new SharpCompressException(
|
||||
"ExtractAllEntries can only be used on solid archives or 7Zip archives (which require random access)."
|
||||
);
|
||||
}
|
||||
await EnsureEntriesLoadedAsync();
|
||||
return await CreateReaderForSolidExtractionAsync();
|
||||
await EnsureEntriesLoadedAsync().ConfigureAwait(false);
|
||||
return await CreateReaderForSolidExtractionAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public virtual ValueTask<bool> IsSolidAsync() => new(false);
|
||||
|
||||
public async ValueTask<bool> IsCompleteAsync()
|
||||
{
|
||||
await EnsureEntriesLoadedAsync();
|
||||
return await EntriesAsync.AllAsync(x => x.IsComplete);
|
||||
await EnsureEntriesLoadedAsync().ConfigureAwait(false);
|
||||
return await EntriesAsync.AllAsync(x => x.IsComplete).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async ValueTask<long> TotalSizeAsync() =>
|
||||
await EntriesAsync.AggregateAsync(0L, (total, cf) => total + cf.CompressedSize);
|
||||
await EntriesAsync
|
||||
.AggregateAsync(0L, (total, cf) => total + cf.CompressedSize)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
public async ValueTask<long> TotalUncompressedSizeAsync() =>
|
||||
await EntriesAsync.AggregateAsync(0L, (total, cf) => total + cf.Size);
|
||||
await EntriesAsync.AggregateAsync(0L, (total, cf) => total + cf.Size).ConfigureAwait(false);
|
||||
|
||||
public ValueTask<bool> IsEncryptedAsync() => new(IsEncrypted);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ public abstract partial class AbstractArchive<TEntry, TVolume> : IArchive, IAsyn
|
||||
private readonly LazyAsyncReadOnlyCollection<TVolume> _lazyVolumesAsync;
|
||||
private readonly LazyAsyncReadOnlyCollection<TEntry> _lazyEntriesAsync;
|
||||
|
||||
protected ReaderOptions ReaderOptions { get; }
|
||||
public ReaderOptions ReaderOptions { get; protected set; }
|
||||
|
||||
internal AbstractArchive(ArchiveType type, SourceStream sourceStream)
|
||||
{
|
||||
|
||||
@@ -6,13 +6,13 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Writers;
|
||||
|
||||
namespace SharpCompress.Archives;
|
||||
|
||||
public abstract partial class AbstractWritableArchive<TEntry, TVolume>
|
||||
public abstract partial class AbstractWritableArchive<TEntry, TVolume, TOptions>
|
||||
where TEntry : IArchiveEntry
|
||||
where TVolume : IVolume
|
||||
where TOptions : IWriterOptions
|
||||
{
|
||||
// Async property moved from main file
|
||||
private IAsyncEnumerable<TEntry> OldEntriesAsync =>
|
||||
@@ -39,7 +39,7 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
|
||||
if (!removedEntries.Contains(entry))
|
||||
{
|
||||
removedEntries.Add(entry);
|
||||
await RebuildModifiedCollectionAsync();
|
||||
await RebuildModifiedCollectionAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
|
||||
}
|
||||
var entry = CreateEntry(key, source, size, modified, closeStream);
|
||||
newEntries.Add(entry);
|
||||
await RebuildModifiedCollectionAsync();
|
||||
await RebuildModifiedCollectionAsync().ConfigureAwait(false);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -106,13 +106,13 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
|
||||
}
|
||||
var entry = CreateDirectoryEntry(key, modified);
|
||||
newEntries.Add(entry);
|
||||
await RebuildModifiedCollectionAsync();
|
||||
await RebuildModifiedCollectionAsync().ConfigureAwait(false);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public async ValueTask SaveToAsync(
|
||||
Stream stream,
|
||||
IWriterOptions options,
|
||||
TOptions options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
@@ -121,4 +121,12 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
|
||||
await SaveToAsync(stream, options, OldEntriesAsync, newEntries, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected abstract ValueTask SaveToAsync(
|
||||
Stream stream,
|
||||
TOptions options,
|
||||
IAsyncEnumerable<TEntry> oldEntries,
|
||||
IEnumerable<TEntry> newEntries,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,18 +11,19 @@ using SharpCompress.Writers;
|
||||
|
||||
namespace SharpCompress.Archives;
|
||||
|
||||
public abstract partial class AbstractWritableArchive<TEntry, TVolume>
|
||||
public abstract partial class AbstractWritableArchive<TEntry, TVolume, TOptions>
|
||||
: AbstractArchive<TEntry, TVolume>,
|
||||
IWritableArchive,
|
||||
IWritableAsyncArchive
|
||||
IWritableArchive<TOptions>,
|
||||
IWritableAsyncArchive<TOptions>
|
||||
where TEntry : IArchiveEntry
|
||||
where TVolume : IVolume
|
||||
where TOptions : IWriterOptions
|
||||
{
|
||||
private class RebuildPauseDisposable : IDisposable
|
||||
{
|
||||
private readonly AbstractWritableArchive<TEntry, TVolume> archive;
|
||||
private readonly AbstractWritableArchive<TEntry, TVolume, TOptions> archive;
|
||||
|
||||
public RebuildPauseDisposable(AbstractWritableArchive<TEntry, TVolume> archive)
|
||||
public RebuildPauseDisposable(AbstractWritableArchive<TEntry, TVolume, TOptions> archive)
|
||||
{
|
||||
this.archive = archive;
|
||||
archive.pauseRebuilding = true;
|
||||
@@ -151,13 +152,15 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
|
||||
long size,
|
||||
DateTime? modified,
|
||||
CancellationToken cancellationToken
|
||||
) => await AddEntryAsync(key, source, closeStream, size, modified, cancellationToken);
|
||||
) =>
|
||||
await AddEntryAsync(key, source, closeStream, size, modified, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
async ValueTask<IArchiveEntry> IWritableAsyncArchive.AddDirectoryEntryAsync(
|
||||
string key,
|
||||
DateTime? modified,
|
||||
CancellationToken cancellationToken
|
||||
) => await AddDirectoryEntryAsync(key, modified, cancellationToken);
|
||||
) => await AddDirectoryEntryAsync(key, modified, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
public TEntry AddDirectoryEntry(string key, DateTime? modified = null)
|
||||
{
|
||||
@@ -175,7 +178,7 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void SaveTo(Stream stream, IWriterOptions options)
|
||||
public void SaveTo(Stream stream, TOptions options)
|
||||
{
|
||||
//reset streams of new entries
|
||||
newEntries.Cast<IWritableArchiveEntry>().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin));
|
||||
@@ -211,19 +214,11 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
|
||||
|
||||
protected abstract void SaveTo(
|
||||
Stream stream,
|
||||
IWriterOptions options,
|
||||
TOptions options,
|
||||
IEnumerable<TEntry> oldEntries,
|
||||
IEnumerable<TEntry> newEntries
|
||||
);
|
||||
|
||||
protected abstract ValueTask SaveToAsync(
|
||||
Stream stream,
|
||||
IWriterOptions options,
|
||||
IAsyncEnumerable<TEntry> oldEntries,
|
||||
IEnumerable<TEntry> newEntries,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
@@ -19,8 +19,9 @@ public static partial class ArchiveFactory
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
readerOptions ??= new ReaderOptions();
|
||||
var factory = await FindFactoryAsync<IArchiveFactory>(stream, cancellationToken);
|
||||
readerOptions ??= ReaderOptions.ForExternalStream;
|
||||
var factory = await FindFactoryAsync<IArchiveFactory>(stream, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return factory.OpenAsyncArchive(stream, readerOptions);
|
||||
}
|
||||
|
||||
@@ -40,9 +41,10 @@ public static partial class ArchiveFactory
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
options ??= new ReaderOptions { LeaveStreamOpen = false };
|
||||
options ??= ReaderOptions.ForOwnedFile;
|
||||
|
||||
var factory = await FindFactoryAsync<IArchiveFactory>(fileInfo, cancellationToken);
|
||||
var factory = await FindFactoryAsync<IArchiveFactory>(fileInfo, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return factory.OpenAsyncArchive(fileInfo, options);
|
||||
}
|
||||
|
||||
@@ -62,14 +64,16 @@ public static partial class ArchiveFactory
|
||||
var fileInfo = filesArray[0];
|
||||
if (filesArray.Length == 1)
|
||||
{
|
||||
return await OpenAsyncArchive(fileInfo, options, cancellationToken);
|
||||
return await OpenAsyncArchive(fileInfo, options, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
fileInfo.NotNull(nameof(fileInfo));
|
||||
options ??= new ReaderOptions { LeaveStreamOpen = false };
|
||||
options ??= ReaderOptions.ForOwnedFile;
|
||||
|
||||
var factory = await FindFactoryAsync<IMultiArchiveFactory>(fileInfo, cancellationToken);
|
||||
return factory.OpenAsyncArchive(filesArray, options, cancellationToken);
|
||||
var factory = await FindFactoryAsync<IMultiArchiveFactory>(fileInfo, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return factory.OpenAsyncArchive(filesArray, options);
|
||||
}
|
||||
|
||||
public static async ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
@@ -89,13 +93,15 @@ public static partial class ArchiveFactory
|
||||
var firstStream = streamsArray[0];
|
||||
if (streamsArray.Length == 1)
|
||||
{
|
||||
return await OpenAsyncArchive(firstStream, options, cancellationToken);
|
||||
return await OpenAsyncArchive(firstStream, options, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
firstStream.NotNull(nameof(firstStream));
|
||||
options ??= new ReaderOptions();
|
||||
options ??= ReaderOptions.ForExternalStream;
|
||||
|
||||
var factory = await FindFactoryAsync<IMultiArchiveFactory>(firstStream, cancellationToken);
|
||||
var factory = await FindFactoryAsync<IMultiArchiveFactory>(firstStream, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return factory.OpenAsyncArchive(streamsArray, options);
|
||||
}
|
||||
|
||||
@@ -117,7 +123,7 @@ public static partial class ArchiveFactory
|
||||
{
|
||||
finfo.NotNull(nameof(finfo));
|
||||
using Stream stream = finfo.OpenRead();
|
||||
return await FindFactoryAsync<T>(stream, cancellationToken);
|
||||
return await FindFactoryAsync<T>(stream, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async ValueTask<T> FindFactoryAsync<T>(
|
||||
@@ -140,7 +146,11 @@ public static partial class ArchiveFactory
|
||||
{
|
||||
stream.Seek(startPosition, SeekOrigin.Begin);
|
||||
|
||||
if (await factory.IsArchiveAsync(stream, cancellationToken: cancellationToken))
|
||||
if (
|
||||
await factory
|
||||
.IsArchiveAsync(stream, cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
stream.Seek(startPosition, SeekOrigin.Begin);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Factories;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
@@ -15,22 +16,23 @@ public static partial class ArchiveFactory
|
||||
{
|
||||
public static IArchive OpenArchive(Stream stream, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
readerOptions ??= new ReaderOptions();
|
||||
readerOptions ??= ReaderOptions.ForExternalStream;
|
||||
return FindFactory<IArchiveFactory>(stream).OpenArchive(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static IWritableArchive CreateArchive(ArchiveType type)
|
||||
public static IWritableArchive<TOptions> CreateArchive<TOptions>()
|
||||
where TOptions : IWriterOptions
|
||||
{
|
||||
var factory = Factory
|
||||
.Factories.OfType<IWriteableArchiveFactory>()
|
||||
.FirstOrDefault(item => item.KnownArchiveType == type);
|
||||
.Factories.OfType<IWriteableArchiveFactory<TOptions>>()
|
||||
.FirstOrDefault();
|
||||
|
||||
if (factory != null)
|
||||
{
|
||||
return factory.CreateArchive();
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Cannot create Archives of type: " + type);
|
||||
throw new NotSupportedException("Cannot create Archives of type: " + typeof(TOptions));
|
||||
}
|
||||
|
||||
public static IArchive OpenArchive(string filePath, ReaderOptions? options = null)
|
||||
@@ -41,7 +43,7 @@ public static partial class ArchiveFactory
|
||||
|
||||
public static IArchive OpenArchive(FileInfo fileInfo, ReaderOptions? options = null)
|
||||
{
|
||||
options ??= new ReaderOptions { LeaveStreamOpen = false };
|
||||
options ??= ReaderOptions.ForOwnedFile;
|
||||
|
||||
return FindFactory<IArchiveFactory>(fileInfo).OpenArchive(fileInfo, options);
|
||||
}
|
||||
@@ -65,7 +67,7 @@ public static partial class ArchiveFactory
|
||||
}
|
||||
|
||||
fileInfo.NotNull(nameof(fileInfo));
|
||||
options ??= new ReaderOptions { LeaveStreamOpen = false };
|
||||
options ??= ReaderOptions.ForOwnedFile;
|
||||
|
||||
return FindFactory<IMultiArchiveFactory>(fileInfo).OpenArchive(filesArray, options);
|
||||
}
|
||||
@@ -86,7 +88,7 @@ public static partial class ArchiveFactory
|
||||
}
|
||||
|
||||
firstStream.NotNull(nameof(firstStream));
|
||||
options ??= new ReaderOptions();
|
||||
options ??= ReaderOptions.ForExternalStream;
|
||||
|
||||
return FindFactory<IMultiArchiveFactory>(firstStream).OpenArchive(streamsArray, options);
|
||||
}
|
||||
@@ -94,11 +96,11 @@ public static partial class ArchiveFactory
|
||||
public static void WriteToDirectory(
|
||||
string sourceArchive,
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null
|
||||
ReaderOptions? options = null
|
||||
)
|
||||
{
|
||||
using var archive = OpenArchive(sourceArchive);
|
||||
archive.WriteToDirectory(destinationDirectory, options);
|
||||
using var archive = OpenArchive(sourceArchive, options);
|
||||
archive.WriteToDirectory(destinationDirectory);
|
||||
}
|
||||
|
||||
public static T FindFactory<T>(string path)
|
||||
|
||||
@@ -6,7 +6,6 @@ using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.GZip;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.GZip;
|
||||
using SharpCompress.Writers;
|
||||
@@ -25,13 +24,13 @@ public partial class GZipArchive
|
||||
)
|
||||
{
|
||||
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
|
||||
await SaveToAsync(stream, new WriterOptions(CompressionType.GZip), cancellationToken)
|
||||
await SaveToAsync(stream, new GZipWriterOptions(CompressionType.GZip), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected override async ValueTask SaveToAsync(
|
||||
Stream stream,
|
||||
IWriterOptions options,
|
||||
GZipWriterOptions options,
|
||||
IAsyncEnumerable<GZipArchiveEntry> oldEntries,
|
||||
IEnumerable<GZipArchiveEntry> newEntries,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -41,7 +40,7 @@ public partial class GZipArchive
|
||||
{
|
||||
throw new InvalidFormatException("Only one entry is allowed in a GZip Archive");
|
||||
}
|
||||
using var writer = new GZipWriter(
|
||||
await using var writer = new GZipWriter(
|
||||
stream,
|
||||
options as GZipWriterOptions ?? new GZipWriterOptions(options)
|
||||
);
|
||||
@@ -51,7 +50,9 @@ public partial class GZipArchive
|
||||
{
|
||||
if (!entry.IsDirectory)
|
||||
{
|
||||
using var entryStream = entry.OpenEntryStream();
|
||||
using var entryStream = await entry
|
||||
.OpenEntryStreamAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await writer
|
||||
.WriteAsync(
|
||||
entry.Key.NotNull("Entry Key is null"),
|
||||
@@ -63,7 +64,9 @@ public partial class GZipArchive
|
||||
}
|
||||
foreach (var entry in newEntries.Where(x => !x.IsDirectory))
|
||||
{
|
||||
using var entryStream = entry.OpenEntryStream();
|
||||
using var entryStream = await entry
|
||||
.OpenEntryStreamAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await writer
|
||||
.WriteAsync(entry.Key.NotNull("Entry Key is null"), entryStream, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
@@ -81,14 +84,13 @@ public partial class GZipArchive
|
||||
IAsyncEnumerable<GZipVolume> volumes
|
||||
)
|
||||
{
|
||||
var stream = (await volumes.SingleAsync()).Stream;
|
||||
var stream = (await volumes.SingleAsync().ConfigureAwait(false)).Stream;
|
||||
yield return new GZipArchiveEntry(
|
||||
this,
|
||||
await GZipFilePart.CreateAsync(
|
||||
stream,
|
||||
ReaderOptions.ArchiveEncoding,
|
||||
ReaderOptions.CompressionProviders
|
||||
)
|
||||
await GZipFilePart
|
||||
.CreateAsync(stream, ReaderOptions.ArchiveEncoding)
|
||||
.ConfigureAwait(false),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,43 +5,41 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.GZip;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.GZip;
|
||||
using SharpCompress.Writers;
|
||||
using SharpCompress.Writers.GZip;
|
||||
|
||||
namespace SharpCompress.Archives.GZip;
|
||||
|
||||
public partial class GZipArchive
|
||||
#if NET8_0_OR_GREATER
|
||||
: IWritableArchiveOpenable,
|
||||
IMultiArchiveOpenable<IWritableArchive, IWritableAsyncArchive>
|
||||
: IWritableArchiveOpenable<GZipWriterOptions>,
|
||||
IMultiArchiveOpenable<
|
||||
IWritableArchive<GZipWriterOptions>,
|
||||
IWritableAsyncArchive<GZipWriterOptions>
|
||||
>
|
||||
#endif
|
||||
{
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return (IWritableAsyncArchive)OpenArchive(
|
||||
new FileInfo(path),
|
||||
readerOptions ?? new ReaderOptions()
|
||||
);
|
||||
return (IWritableAsyncArchive<GZipWriterOptions>)
|
||||
OpenArchive(new FileInfo(path), readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
public static IWritableArchive OpenArchive(string filePath, ReaderOptions? readerOptions = null)
|
||||
public static IWritableArchive<GZipWriterOptions> OpenArchive(
|
||||
string filePath,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
filePath.NotNullOrEmpty(nameof(filePath));
|
||||
return OpenArchive(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
public static IWritableArchive OpenArchive(
|
||||
public static IWritableArchive<GZipWriterOptions> OpenArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
@@ -56,7 +54,7 @@ public partial class GZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IWritableArchive OpenArchive(
|
||||
public static IWritableArchive<GZipWriterOptions> OpenArchive(
|
||||
IEnumerable<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
@@ -72,7 +70,7 @@ public partial class GZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IWritableArchive OpenArchive(
|
||||
public static IWritableArchive<GZipWriterOptions> OpenArchive(
|
||||
IEnumerable<Stream> streams,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
@@ -88,7 +86,10 @@ public partial class GZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IWritableArchive OpenArchive(Stream stream, ReaderOptions? readerOptions = null)
|
||||
public static IWritableArchive<GZipWriterOptions> OpenArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
stream.NotNull(nameof(stream));
|
||||
|
||||
@@ -102,49 +103,30 @@ public partial class GZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IWritableAsyncArchive)OpenArchive(stream, readerOptions);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(stream, readerOptions);
|
||||
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(fileInfo, readerOptions);
|
||||
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IWritableAsyncArchive)OpenArchive(streams, readerOptions);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(streams, readerOptions);
|
||||
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(fileInfos, readerOptions);
|
||||
|
||||
public static IWritableArchive CreateArchive() => new GZipArchive();
|
||||
public static IWritableArchive<GZipWriterOptions> CreateArchive() => new GZipArchive();
|
||||
|
||||
public static IWritableAsyncArchive CreateAsyncArchive() => new GZipArchive();
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> CreateAsyncArchive() =>
|
||||
new GZipArchive();
|
||||
|
||||
public static bool IsGZipFile(string filePath) => IsGZipFile(new FileInfo(filePath));
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@ using System;
|
||||
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.Common.Options;
|
||||
@@ -15,7 +13,8 @@ using SharpCompress.Writers.GZip;
|
||||
|
||||
namespace SharpCompress.Archives.GZip;
|
||||
|
||||
public partial class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
|
||||
public partial class GZipArchive
|
||||
: AbstractWritableArchive<GZipArchiveEntry, GZipVolume, GZipWriterOptions>
|
||||
{
|
||||
private GZipArchive(SourceStream sourceStream)
|
||||
: base(ArchiveType.GZip, sourceStream) { }
|
||||
@@ -34,7 +33,7 @@ public partial class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZi
|
||||
public void SaveTo(FileInfo fileInfo)
|
||||
{
|
||||
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
|
||||
SaveTo(stream, new WriterOptions(CompressionType.GZip));
|
||||
SaveTo(stream, new GZipWriterOptions(CompressionType.GZip));
|
||||
}
|
||||
|
||||
protected override GZipArchiveEntry CreateEntryInternal(
|
||||
@@ -59,7 +58,7 @@ public partial class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZi
|
||||
|
||||
protected override void SaveTo(
|
||||
Stream stream,
|
||||
IWriterOptions options,
|
||||
GZipWriterOptions options,
|
||||
IEnumerable<GZipArchiveEntry> oldEntries,
|
||||
IEnumerable<GZipArchiveEntry> newEntries
|
||||
)
|
||||
@@ -88,11 +87,8 @@ public partial class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZi
|
||||
var stream = volumes.Single().Stream;
|
||||
yield return new GZipArchiveEntry(
|
||||
this,
|
||||
GZipFilePart.Create(
|
||||
stream,
|
||||
ReaderOptions.ArchiveEncoding,
|
||||
ReaderOptions.CompressionProviders
|
||||
)
|
||||
GZipFilePart.Create(stream, ReaderOptions.ArchiveEncoding),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.GZip;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
namespace SharpCompress.Archives.GZip;
|
||||
|
||||
public class GZipArchiveEntry : GZipEntry, IArchiveEntry
|
||||
{
|
||||
internal GZipArchiveEntry(GZipArchive archive, GZipFilePart? part)
|
||||
: base(part) => Archive = archive;
|
||||
internal GZipArchiveEntry(GZipArchive archive, GZipFilePart? part, IReaderOptions readerOptions)
|
||||
: base(part, readerOptions) => Archive = archive;
|
||||
|
||||
public virtual Stream OpenEntryStream()
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ internal sealed class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArch
|
||||
DateTime? lastModified,
|
||||
bool closeStream
|
||||
)
|
||||
: base(archive, null)
|
||||
: base(archive, null, archive.ReaderOptions)
|
||||
{
|
||||
this.stream = stream;
|
||||
Key = path;
|
||||
|
||||
@@ -12,6 +12,11 @@ public interface IArchive : IDisposable
|
||||
|
||||
ArchiveType Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The options used when opening this archive, including extraction behavior settings.
|
||||
/// </summary>
|
||||
ReaderOptions ReaderOptions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Use this method to extract all entries in an archive in order.
|
||||
/// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be
|
||||
|
||||
@@ -47,11 +47,13 @@ public static class IArchiveEntryExtensions
|
||||
}
|
||||
|
||||
#if LEGACY_DOTNET
|
||||
using var entryStream = await archiveEntry.OpenEntryStreamAsync(cancellationToken);
|
||||
using var entryStream = await archiveEntry
|
||||
.OpenEntryStreamAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
#else
|
||||
await using var entryStream = await archiveEntry.OpenEntryStreamAsync(
|
||||
cancellationToken
|
||||
);
|
||||
await using var entryStream = await archiveEntry
|
||||
.OpenEntryStreamAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
#endif
|
||||
var sourceStream = WrapWithProgress(entryStream, archiveEntry, progress);
|
||||
await sourceStream
|
||||
@@ -100,15 +102,11 @@ public static class IArchiveEntryExtensions
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
public void WriteToDirectory(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null
|
||||
) =>
|
||||
public void WriteToDirectory(string destinationDirectory) =>
|
||||
ExtractionMethods.WriteEntryToDirectory(
|
||||
entry,
|
||||
destinationDirectory,
|
||||
options,
|
||||
entry.WriteToFile
|
||||
(path) => entry.WriteToFile(path)
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
@@ -116,15 +114,14 @@ public static class IArchiveEntryExtensions
|
||||
/// </summary>
|
||||
public async ValueTask WriteToDirectoryAsync(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
await ExtractionMethods
|
||||
.WriteEntryToDirectoryAsync(
|
||||
entry,
|
||||
destinationDirectory,
|
||||
options,
|
||||
entry.WriteToFileAsync,
|
||||
async (path, ct) =>
|
||||
await entry.WriteToFileAsync(path, ct).ConfigureAwait(false),
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
@@ -132,11 +129,10 @@ public static class IArchiveEntryExtensions
|
||||
/// <summary>
|
||||
/// Extract to specific file
|
||||
/// </summary>
|
||||
public void WriteToFile(string destinationFileName, ExtractionOptions? options = null) =>
|
||||
public void WriteToFile(string destinationFileName) =>
|
||||
ExtractionMethods.WriteEntryToFile(
|
||||
entry,
|
||||
destinationFileName,
|
||||
options,
|
||||
(x, fm) =>
|
||||
{
|
||||
using var fs = File.Open(destinationFileName, fm);
|
||||
@@ -149,14 +145,12 @@ public static class IArchiveEntryExtensions
|
||||
/// </summary>
|
||||
public async ValueTask WriteToFileAsync(
|
||||
string destinationFileName,
|
||||
ExtractionOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
await ExtractionMethods
|
||||
.WriteEntryToFileAsync(
|
||||
entry,
|
||||
destinationFileName,
|
||||
options,
|
||||
async (x, fm, ct) =>
|
||||
{
|
||||
using var fs = File.Open(destinationFileName, fm);
|
||||
|
||||
@@ -14,28 +14,25 @@ public static class IArchiveExtensions
|
||||
/// Extract to specific directory with progress reporting
|
||||
/// </summary>
|
||||
/// <param name="destinationDirectory">The folder to extract into.</param>
|
||||
/// <param name="options">Extraction options.</param>
|
||||
/// <param name="progress">Optional progress reporter for tracking extraction progress.</param>
|
||||
public void WriteToDirectory(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null,
|
||||
IProgress<ProgressReport>? progress = null
|
||||
)
|
||||
{
|
||||
if (archive.IsSolid || archive.Type == ArchiveType.SevenZip)
|
||||
{
|
||||
using var reader = archive.ExtractAllEntries();
|
||||
reader.WriteAllToDirectory(destinationDirectory, options);
|
||||
reader.WriteAllToDirectory(destinationDirectory);
|
||||
}
|
||||
else
|
||||
{
|
||||
archive.WriteToDirectoryInternal(destinationDirectory, options, progress);
|
||||
archive.WriteToDirectoryInternal(destinationDirectory, progress);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteToDirectoryInternal(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options,
|
||||
IProgress<ProgressReport>? progress
|
||||
)
|
||||
{
|
||||
@@ -61,7 +58,7 @@ public static class IArchiveExtensions
|
||||
continue;
|
||||
}
|
||||
|
||||
entry.WriteToDirectory(destinationDirectory, options);
|
||||
entry.WriteToDirectory(destinationDirectory);
|
||||
|
||||
bytesRead += entry.Size;
|
||||
progress?.Report(
|
||||
|
||||
@@ -20,20 +20,17 @@ public interface IArchiveOpenable<TSync, TASync>
|
||||
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,44 +17,45 @@ public static class IAsyncArchiveExtensions
|
||||
/// </summary>
|
||||
/// <param name="archive">The archive to extract.</param>
|
||||
/// <param name="destinationDirectory">The folder to extract into.</param>
|
||||
/// <param name="options">Extraction options.</param>
|
||||
/// <param name="progress">Optional progress reporter for tracking extraction progress.</param>
|
||||
/// <param name="cancellationToken">Optional cancellation token.</param>
|
||||
public async ValueTask WriteToDirectoryAsync(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null,
|
||||
IProgress<ProgressReport>? progress = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (await archive.IsSolidAsync() || archive.Type == ArchiveType.SevenZip)
|
||||
if (
|
||||
await archive.IsSolidAsync().ConfigureAwait(false)
|
||||
|| archive.Type == ArchiveType.SevenZip
|
||||
)
|
||||
{
|
||||
await using var reader = await archive.ExtractAllEntriesAsync();
|
||||
await reader.WriteAllToDirectoryAsync(
|
||||
destinationDirectory,
|
||||
options,
|
||||
cancellationToken
|
||||
);
|
||||
await using var reader = await archive
|
||||
.ExtractAllEntriesAsync()
|
||||
.ConfigureAwait(false);
|
||||
await reader
|
||||
.WriteAllToDirectoryAsync(destinationDirectory, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await archive.WriteToDirectoryAsyncInternal(
|
||||
destinationDirectory,
|
||||
options,
|
||||
progress,
|
||||
cancellationToken
|
||||
);
|
||||
await archive
|
||||
.WriteToDirectoryAsyncInternal(
|
||||
destinationDirectory,
|
||||
progress,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask WriteToDirectoryAsyncInternal(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options,
|
||||
IProgress<ProgressReport>? progress,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var totalBytes = await archive.TotalUncompressedSizeAsync();
|
||||
var totalBytes = await archive.TotalUncompressedSizeAsync().ConfigureAwait(false);
|
||||
var bytesRead = 0L;
|
||||
var seenDirectories = new HashSet<string>();
|
||||
|
||||
@@ -79,7 +80,7 @@ public static class IAsyncArchiveExtensions
|
||||
}
|
||||
|
||||
await entry
|
||||
.WriteToDirectoryAsync(destinationDirectory, options, cancellationToken)
|
||||
.WriteToDirectoryAsync(destinationDirectory, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
bytesRead += entry.Size;
|
||||
|
||||
@@ -50,10 +50,8 @@ public interface IMultiArchiveFactory : IFactory
|
||||
/// </summary>
|
||||
/// <param name="fileInfos"></param>
|
||||
/// <param name="readerOptions">reading options.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
IAsyncArchive OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,14 +22,12 @@ public interface IMultiArchiveOpenable<TSync, TASync>
|
||||
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -28,28 +28,23 @@ public interface IWritableArchive : IArchive, IWritableArchiveCommon
|
||||
|
||||
IArchiveEntry AddDirectoryEntry(string key, DateTime? modified = null);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the archive to the specified stream using the given writer options.
|
||||
/// </summary>
|
||||
void SaveTo(Stream stream, IWriterOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the specified entry from the archive.
|
||||
/// </summary>
|
||||
void RemoveEntry(IArchiveEntry entry);
|
||||
}
|
||||
|
||||
public interface IWritableAsyncArchive : IAsyncArchive, IWritableArchiveCommon
|
||||
public interface IWritableArchive<TOptions> : IWritableArchive
|
||||
where TOptions : IWriterOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Asynchronously saves the archive to the specified stream using the given writer options.
|
||||
/// Saves the archive to the specified stream using the given writer options.
|
||||
/// </summary>
|
||||
ValueTask SaveToAsync(
|
||||
Stream stream,
|
||||
IWriterOptions options,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
void SaveTo(Stream stream, TOptions options);
|
||||
}
|
||||
|
||||
public interface IWritableAsyncArchive : IAsyncArchive, IWritableArchiveCommon
|
||||
{
|
||||
/// <summary>
|
||||
/// Asynchronously adds an entry to the archive with the specified key, source stream, and options.
|
||||
/// </summary>
|
||||
@@ -76,3 +71,16 @@ public interface IWritableAsyncArchive : IAsyncArchive, IWritableArchiveCommon
|
||||
/// </summary>
|
||||
ValueTask RemoveEntryAsync(IArchiveEntry entry);
|
||||
}
|
||||
|
||||
public interface IWritableAsyncArchive<TOptions> : IWritableAsyncArchive
|
||||
where TOptions : IWriterOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Asynchronously saves the archive to the specified stream using the given writer options.
|
||||
/// </summary>
|
||||
ValueTask SaveToAsync(
|
||||
Stream stream,
|
||||
TOptions options,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
}
|
||||
|
||||
@@ -58,17 +58,23 @@ public static class IWritableArchiveExtensions
|
||||
fileInfo.LastWriteTime
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveTo(string filePath, IWriterOptions? options = null) =>
|
||||
writableArchive.SaveTo(
|
||||
new FileInfo(filePath),
|
||||
options ?? new WriterOptions(CompressionType.Deflate)
|
||||
);
|
||||
public static void SaveTo<TOptions>(
|
||||
this IWritableArchive<TOptions> writableArchive,
|
||||
string filePath,
|
||||
TOptions options
|
||||
)
|
||||
where TOptions : IWriterOptions => writableArchive.SaveTo(new FileInfo(filePath), options);
|
||||
|
||||
public void SaveTo(FileInfo fileInfo, IWriterOptions? options = null)
|
||||
{
|
||||
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
|
||||
writableArchive.SaveTo(stream, options ?? new WriterOptions(CompressionType.Deflate));
|
||||
}
|
||||
public static void SaveTo<TOptions>(
|
||||
this IWritableArchive<TOptions> writableArchive,
|
||||
FileInfo fileInfo,
|
||||
TOptions options
|
||||
)
|
||||
where TOptions : IWriterOptions
|
||||
{
|
||||
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
|
||||
writableArchive.SaveTo(stream, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
namespace SharpCompress.Archives;
|
||||
|
||||
public interface IWritableArchiveOpenable
|
||||
: IArchiveOpenable<IWritableArchive, IWritableAsyncArchive>
|
||||
public interface IWritableArchiveOpenable<TOptions>
|
||||
: IArchiveOpenable<IWritableArchive<TOptions>, IWritableAsyncArchive<TOptions>>
|
||||
where TOptions : IWriterOptions
|
||||
{
|
||||
public static abstract IWritableArchive CreateArchive();
|
||||
public static abstract IWritableAsyncArchive CreateAsyncArchive();
|
||||
public static abstract IWritableArchive<TOptions> CreateArchive();
|
||||
public static abstract IWritableAsyncArchive<TOptions> CreateAsyncArchive();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -25,13 +25,15 @@ public static class IWritableAsyncArchiveExtensions
|
||||
)
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
await writableArchive.AddEntryAsync(
|
||||
path.Substring(filePath.Length),
|
||||
fileInfo.OpenRead(),
|
||||
true,
|
||||
fileInfo.Length,
|
||||
fileInfo.LastWriteTime
|
||||
);
|
||||
await writableArchive
|
||||
.AddEntryAsync(
|
||||
path.Substring(filePath.Length),
|
||||
fileInfo.OpenRead(),
|
||||
true,
|
||||
fileInfo.Length,
|
||||
fileInfo.LastWriteTime
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,32 +62,26 @@ public static class IWritableAsyncArchiveExtensions
|
||||
fileInfo.LastWriteTime
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask SaveToAsync(
|
||||
string filePath,
|
||||
IWriterOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
writableArchive.SaveToAsync(
|
||||
new FileInfo(filePath),
|
||||
options ?? new WriterOptions(CompressionType.Deflate),
|
||||
cancellationToken
|
||||
);
|
||||
public static ValueTask SaveToAsync<TOptions>(
|
||||
this IWritableAsyncArchive<TOptions> writableArchive,
|
||||
string filePath,
|
||||
TOptions options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
where TOptions : IWriterOptions =>
|
||||
writableArchive.SaveToAsync(new FileInfo(filePath), options, cancellationToken);
|
||||
|
||||
public async ValueTask SaveToAsync(
|
||||
FileInfo fileInfo,
|
||||
IWriterOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
|
||||
await writableArchive
|
||||
.SaveToAsync(
|
||||
stream,
|
||||
options ?? new WriterOptions(CompressionType.Deflate),
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
public static async ValueTask SaveToAsync<TOptions>(
|
||||
this IWritableAsyncArchive<TOptions> writableArchive,
|
||||
FileInfo fileInfo,
|
||||
TOptions options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
where TOptions : IWriterOptions
|
||||
{
|
||||
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
|
||||
await writableArchive.SaveToAsync(stream, options, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
namespace SharpCompress.Archives;
|
||||
|
||||
/// <summary>
|
||||
@@ -10,11 +12,12 @@ namespace SharpCompress.Archives;
|
||||
/// <item><see cref="Factories.ZipFactory"/></item>
|
||||
/// <item><see cref="Factories.GZipFactory"/></item>
|
||||
/// </list>
|
||||
public interface IWriteableArchiveFactory : Factories.IFactory
|
||||
public interface IWriteableArchiveFactory<TOptions> : Factories.IFactory
|
||||
where TOptions : IWriterOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new, empty archive, ready to be written.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IWritableArchive CreateArchive();
|
||||
IWritableArchive<TOptions> CreateArchive();
|
||||
}
|
||||
|
||||
@@ -25,13 +25,13 @@ public partial class RarArchive
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
await base.DisposeAsync();
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async ValueTask<IAsyncReader> CreateReaderForSolidExtractionAsync()
|
||||
{
|
||||
if (await this.IsMultipartVolumeAsync())
|
||||
if (await this.IsMultipartVolumeAsync().ConfigureAwait(false))
|
||||
{
|
||||
var streams = await VolumesAsync
|
||||
.Select(volume =>
|
||||
@@ -39,15 +39,18 @@ public partial class RarArchive
|
||||
volume.Stream.Position = 0;
|
||||
return volume.Stream;
|
||||
})
|
||||
.ToListAsync();
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
return (RarReader)RarReader.OpenReader(streams, ReaderOptions);
|
||||
}
|
||||
|
||||
var stream = (await VolumesAsync.FirstAsync()).Stream;
|
||||
var stream = (await VolumesAsync.FirstAsync().ConfigureAwait(false)).Stream;
|
||||
stream.Position = 0;
|
||||
return (RarReader)RarReader.OpenReader(stream, ReaderOptions);
|
||||
}
|
||||
|
||||
public override async ValueTask<bool> IsSolidAsync() =>
|
||||
await (await VolumesAsync.CastAsync<RarVolume>().FirstAsync()).IsSolidArchiveAsync();
|
||||
await (await VolumesAsync.CastAsync<RarVolume>().FirstAsync().ConfigureAwait(false))
|
||||
.IsSolidArchiveAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -25,12 +25,16 @@ public static class RarArchiveExtensions
|
||||
/// RarArchive is the first volume of a multi-part archive. If MultipartVolume is true and IsFirstVolume is false then the first volume file must be missing.
|
||||
/// </summary>
|
||||
public async ValueTask<bool> IsFirstVolumeAsync() =>
|
||||
(await archive.VolumesAsync.CastAsync<RarVolume>().FirstAsync()).IsFirstVolume;
|
||||
(
|
||||
await archive.VolumesAsync.CastAsync<RarVolume>().FirstAsync().ConfigureAwait(false)
|
||||
).IsFirstVolume;
|
||||
|
||||
/// <summary>
|
||||
/// RarArchive is part of a multi-part archive.
|
||||
/// </summary>
|
||||
public async ValueTask<bool> IsMultipartVolumeAsync() =>
|
||||
(await archive.VolumesAsync.CastAsync<RarVolume>().FirstAsync()).IsMultiVolume;
|
||||
(
|
||||
await archive.VolumesAsync.CastAsync<RarVolume>().FirstAsync().ConfigureAwait(false)
|
||||
).IsMultiVolume;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,9 @@ public partial class RarArchive
|
||||
{
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return (IRarAsyncArchive)OpenArchive(new FileInfo(path), readerOptions);
|
||||
}
|
||||
@@ -102,41 +100,33 @@ public partial class RarArchive
|
||||
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IRarAsyncArchive)OpenArchive(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IRarAsyncArchive)OpenArchive(fileInfo, readerOptions);
|
||||
}
|
||||
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IRarAsyncArchive)OpenArchive(streams, readerOptions);
|
||||
}
|
||||
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IRarAsyncArchive)OpenArchive(fileInfos, readerOptions);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ public partial class RarArchiveEntry
|
||||
stream = new RarStream(
|
||||
archive.UnpackV1.Value,
|
||||
FileHeader,
|
||||
await MultiVolumeReadOnlyAsyncStream.Create(
|
||||
Parts.ToAsyncEnumerable().CastAsync<RarFilePart>()
|
||||
)
|
||||
await MultiVolumeReadOnlyAsyncStream
|
||||
.Create(Parts.ToAsyncEnumerable().CastAsync<RarFilePart>())
|
||||
.ConfigureAwait(false)
|
||||
);
|
||||
}
|
||||
else
|
||||
@@ -31,13 +31,13 @@ public partial class RarArchiveEntry
|
||||
stream = new RarStream(
|
||||
archive.UnpackV2017.Value,
|
||||
FileHeader,
|
||||
await MultiVolumeReadOnlyAsyncStream.Create(
|
||||
Parts.ToAsyncEnumerable().CastAsync<RarFilePart>()
|
||||
)
|
||||
await MultiVolumeReadOnlyAsyncStream
|
||||
.Create(Parts.ToAsyncEnumerable().CastAsync<RarFilePart>())
|
||||
.ConfigureAwait(false)
|
||||
);
|
||||
}
|
||||
|
||||
await stream.InitializeAsync(cancellationToken);
|
||||
await stream.InitializeAsync(cancellationToken).ConfigureAwait(false);
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ public partial class RarArchiveEntry : RarEntry, IArchiveEntry
|
||||
IEnumerable<RarFilePart> parts,
|
||||
ReaderOptions readerOptions
|
||||
)
|
||||
: base(readerOptions)
|
||||
{
|
||||
this.parts = parts.ToList();
|
||||
this.archive = archive;
|
||||
|
||||
@@ -21,15 +21,12 @@ public partial class SevenZipArchive
|
||||
{
|
||||
stream.Position = 0;
|
||||
var reader = new ArchiveReader();
|
||||
await reader.OpenAsync(
|
||||
stream,
|
||||
lookForHeader: ReaderOptions.LookForHeader,
|
||||
cancellationToken
|
||||
);
|
||||
_database = await reader.ReadDatabaseAsync(
|
||||
new PasswordProvider(ReaderOptions.Password),
|
||||
cancellationToken
|
||||
);
|
||||
await reader
|
||||
.OpenAsync(stream, lookForHeader: ReaderOptions.LookForHeader, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
_database = await reader
|
||||
.ReadDatabaseAsync(new PasswordProvider(ReaderOptions.Password), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +34,8 @@ public partial class SevenZipArchive
|
||||
IAsyncEnumerable<SevenZipVolume> volumes
|
||||
)
|
||||
{
|
||||
var stream = (await volumes.SingleAsync()).Stream;
|
||||
await LoadFactoryAsync(stream);
|
||||
var stream = (await volumes.SingleAsync().ConfigureAwait(false)).Stream;
|
||||
await LoadFactoryAsync(stream).ConfigureAwait(false);
|
||||
if (_database is null)
|
||||
{
|
||||
yield break;
|
||||
@@ -49,7 +46,8 @@ public partial class SevenZipArchive
|
||||
var file = _database._files[i];
|
||||
entries[i] = new SevenZipArchiveEntry(
|
||||
this,
|
||||
new SevenZipFilePart(stream, _database, i, file, ReaderOptions.ArchiveEncoding)
|
||||
new SevenZipFilePart(stream, _database, i, file, ReaderOptions.ArchiveEncoding),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
foreach (var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder))
|
||||
|
||||
@@ -16,13 +16,8 @@ public partial class SevenZipArchive
|
||||
IMultiArchiveOpenable<IArchive, IAsyncArchive>
|
||||
#endif
|
||||
{
|
||||
public static IAsyncArchive OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncArchive OpenAsyncArchive(string path, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty("path");
|
||||
return (IAsyncArchive)OpenArchive(new FileInfo(path), readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
@@ -91,43 +86,32 @@ public partial class SevenZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IAsyncArchive OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IAsyncArchive)OpenArchive(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static IAsyncArchive OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IAsyncArchive)OpenArchive(fileInfo, readerOptions);
|
||||
}
|
||||
|
||||
public static IAsyncArchive OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IAsyncArchive)OpenArchive(streams, readerOptions);
|
||||
}
|
||||
|
||||
public static IAsyncArchive OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IAsyncArchive)OpenArchive(fileInfos, readerOptions);
|
||||
}
|
||||
|
||||
@@ -163,7 +147,7 @@ public partial class SevenZipArchive
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
try
|
||||
{
|
||||
return await SignatureMatchAsync(stream, cancellationToken);
|
||||
return await SignatureMatchAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -55,7 +55,8 @@ public partial class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, Sev
|
||||
i,
|
||||
file,
|
||||
ReaderOptions.ArchiveEncoding
|
||||
)
|
||||
),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
foreach (
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.SevenZip;
|
||||
|
||||
namespace SharpCompress.Archives.SevenZip;
|
||||
|
||||
public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry
|
||||
{
|
||||
internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part)
|
||||
: base(part) => Archive = archive;
|
||||
internal SevenZipArchiveEntry(
|
||||
SevenZipArchive archive,
|
||||
SevenZipFilePart part,
|
||||
IReaderOptions readerOptions
|
||||
)
|
||||
: base(part, readerOptions) => Archive = archive;
|
||||
|
||||
public Stream OpenEntryStream() => FilePart.GetCompressedStream();
|
||||
|
||||
public async ValueTask<Stream> OpenEntryStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
) => (await FilePart.GetCompressedStreamAsync(cancellationToken)).NotNull();
|
||||
) =>
|
||||
(
|
||||
await FilePart.GetCompressedStreamAsync(cancellationToken).ConfigureAwait(false)
|
||||
).NotNull();
|
||||
|
||||
public IArchive Archive { get; }
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ public partial class TarArchive
|
||||
{
|
||||
protected override async ValueTask SaveToAsync(
|
||||
Stream stream,
|
||||
IWriterOptions options,
|
||||
TarWriterOptions options,
|
||||
IAsyncEnumerable<TarArchiveEntry> oldEntries,
|
||||
IEnumerable<TarArchiveEntry> newEntries,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -96,7 +96,7 @@ public partial class TarArchive
|
||||
IAsyncEnumerable<TarVolume> volumes
|
||||
)
|
||||
{
|
||||
var stream = (await volumes.SingleAsync()).Stream;
|
||||
var stream = (await volumes.SingleAsync().ConfigureAwait(false)).Stream;
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
stream.Position = 0;
|
||||
@@ -127,7 +127,8 @@ public partial class TarArchive
|
||||
var entry = new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(previousHeader, stream),
|
||||
CompressionType.None
|
||||
CompressionType.None,
|
||||
ReaderOptions
|
||||
);
|
||||
|
||||
var oldStreamPos = stream.Position;
|
||||
@@ -135,7 +136,7 @@ public partial class TarArchive
|
||||
using (var entryStream = entry.OpenEntryStream())
|
||||
{
|
||||
using var memoryStream = new MemoryStream();
|
||||
await entryStream.CopyToAsync(memoryStream);
|
||||
await entryStream.CopyToAsync(memoryStream).ConfigureAwait(false);
|
||||
memoryStream.Position = 0;
|
||||
var bytes = memoryStream.ToArray();
|
||||
|
||||
@@ -151,7 +152,8 @@ public partial class TarArchive
|
||||
yield return new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(header, stream),
|
||||
CompressionType.None
|
||||
CompressionType.None,
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,22 +9,29 @@ using SharpCompress.Common;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Writers.Tar;
|
||||
|
||||
namespace SharpCompress.Archives.Tar;
|
||||
|
||||
public partial class TarArchive
|
||||
#if NET8_0_OR_GREATER
|
||||
: IWritableArchiveOpenable,
|
||||
IMultiArchiveOpenable<IWritableArchive, IWritableAsyncArchive>
|
||||
: IWritableArchiveOpenable<TarWriterOptions>,
|
||||
IMultiArchiveOpenable<
|
||||
IWritableArchive<TarWriterOptions>,
|
||||
IWritableAsyncArchive<TarWriterOptions>
|
||||
>
|
||||
#endif
|
||||
{
|
||||
public static IWritableArchive OpenArchive(string filePath, ReaderOptions? readerOptions = null)
|
||||
public static IWritableArchive<TarWriterOptions> OpenArchive(
|
||||
string filePath,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
filePath.NotNullOrEmpty(nameof(filePath));
|
||||
return OpenArchive(new FileInfo(filePath), readerOptions);
|
||||
}
|
||||
|
||||
public static IWritableArchive OpenArchive(
|
||||
public static IWritableArchive<TarWriterOptions> OpenArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
@@ -39,7 +46,7 @@ public partial class TarArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IWritableArchive OpenArchive(
|
||||
public static IWritableArchive<TarWriterOptions> OpenArchive(
|
||||
IEnumerable<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
@@ -55,7 +62,7 @@ public partial class TarArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IWritableArchive OpenArchive(
|
||||
public static IWritableArchive<TarWriterOptions> OpenArchive(
|
||||
IEnumerable<Stream> streams,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
@@ -71,7 +78,10 @@ public partial class TarArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IWritableArchive OpenArchive(Stream stream, ReaderOptions? readerOptions = null)
|
||||
public static IWritableArchive<TarWriterOptions> OpenArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
stream.NotNull(nameof(stream));
|
||||
|
||||
@@ -85,55 +95,30 @@ public partial class TarArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IWritableAsyncArchive)OpenArchive(stream, readerOptions);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(stream, readerOptions);
|
||||
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IWritableAsyncArchive)OpenArchive(new FileInfo(path), readerOptions);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(new FileInfo(path), readerOptions);
|
||||
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(fileInfo, readerOptions);
|
||||
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IWritableAsyncArchive)OpenArchive(streams, readerOptions);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(streams, readerOptions);
|
||||
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(fileInfos, readerOptions);
|
||||
|
||||
public static bool IsTarFile(string filePath) => IsTarFile(new FileInfo(filePath));
|
||||
|
||||
@@ -181,7 +166,7 @@ public partial class TarArchive
|
||||
#else
|
||||
using var reader = new AsyncBinaryReader(stream, leaveOpen: true);
|
||||
#endif
|
||||
var readSucceeded = await tarHeader.ReadAsync(reader);
|
||||
var readSucceeded = await tarHeader.ReadAsync(reader).ConfigureAwait(false);
|
||||
var isEmptyArchive =
|
||||
tarHeader.Name?.Length == 0
|
||||
&& tarHeader.Size == 0
|
||||
@@ -196,7 +181,7 @@ public partial class TarArchive
|
||||
}
|
||||
}
|
||||
|
||||
public static IWritableArchive CreateArchive() => new TarArchive();
|
||||
public static IWritableArchive<TarWriterOptions> CreateArchive() => new TarArchive();
|
||||
|
||||
public static IWritableAsyncArchive CreateAsyncArchive() => new TarArchive();
|
||||
public static IWritableAsyncArchive<TarWriterOptions> CreateAsyncArchive() => new TarArchive();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ using SharpCompress.Writers.Tar;
|
||||
|
||||
namespace SharpCompress.Archives.Tar;
|
||||
|
||||
public partial class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
|
||||
public partial class TarArchive
|
||||
: AbstractWritableArchive<TarArchiveEntry, TarVolume, TarWriterOptions>
|
||||
{
|
||||
protected override IEnumerable<TarVolume> LoadVolumes(SourceStream sourceStream)
|
||||
{
|
||||
@@ -59,7 +60,8 @@ public partial class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVo
|
||||
var entry = new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(previousHeader, stream),
|
||||
CompressionType.None
|
||||
CompressionType.None,
|
||||
ReaderOptions
|
||||
);
|
||||
|
||||
var oldStreamPos = stream.Position;
|
||||
@@ -81,7 +83,8 @@ public partial class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVo
|
||||
yield return new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(header, stream),
|
||||
CompressionType.None
|
||||
CompressionType.None,
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -116,7 +119,7 @@ public partial class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVo
|
||||
|
||||
protected override void SaveTo(
|
||||
Stream stream,
|
||||
IWriterOptions options,
|
||||
TarWriterOptions options,
|
||||
IEnumerable<TarArchiveEntry> oldEntries,
|
||||
IEnumerable<TarArchiveEntry> newEntries
|
||||
)
|
||||
|
||||
@@ -1,22 +1,31 @@
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Tar;
|
||||
|
||||
namespace SharpCompress.Archives.Tar;
|
||||
|
||||
public class TarArchiveEntry : TarEntry, IArchiveEntry
|
||||
{
|
||||
internal TarArchiveEntry(TarArchive archive, TarFilePart? part, CompressionType compressionType)
|
||||
: base(part, compressionType) => Archive = archive;
|
||||
internal TarArchiveEntry(
|
||||
TarArchive archive,
|
||||
TarFilePart? part,
|
||||
CompressionType compressionType,
|
||||
IReaderOptions readerOptions
|
||||
)
|
||||
: base(part, compressionType, readerOptions) => Archive = archive;
|
||||
|
||||
public virtual Stream OpenEntryStream() => Parts.Single().GetCompressedStream().NotNull();
|
||||
|
||||
public async ValueTask<Stream> OpenEntryStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
) => (await Parts.Single().GetCompressedStreamAsync(cancellationToken)).NotNull();
|
||||
) =>
|
||||
(
|
||||
await Parts.Single().GetCompressedStreamAsync(cancellationToken).ConfigureAwait(false)
|
||||
).NotNull();
|
||||
|
||||
#region IArchiveEntry Members
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ internal sealed class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiv
|
||||
DateTime? lastModified,
|
||||
bool closeStream
|
||||
)
|
||||
: base(archive, null, compressionType)
|
||||
: base(archive, null, compressionType, archive.ReaderOptions)
|
||||
{
|
||||
this.stream = stream;
|
||||
Key = path;
|
||||
@@ -36,7 +36,7 @@ internal sealed class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiv
|
||||
string directoryPath,
|
||||
DateTime? lastModified
|
||||
)
|
||||
: base(archive, null, CompressionType.None)
|
||||
: base(archive, null, CompressionType.None, archive.ReaderOptions)
|
||||
{
|
||||
stream = null;
|
||||
Key = directoryPath;
|
||||
|
||||
@@ -21,7 +21,7 @@ public partial class ZipArchive
|
||||
IAsyncEnumerable<ZipVolume> volumes
|
||||
)
|
||||
{
|
||||
var vols = await volumes.ToListAsync();
|
||||
var vols = await volumes.ToListAsync().ConfigureAwait(false);
|
||||
var volsArray = vols.ToArray();
|
||||
|
||||
await foreach (
|
||||
@@ -55,12 +55,8 @@ public partial class ZipArchive
|
||||
|
||||
yield return new ZipArchiveEntry(
|
||||
this,
|
||||
new SeekableZipFilePart(
|
||||
headerFactory.NotNull(),
|
||||
deh,
|
||||
s,
|
||||
ReaderOptions.CompressionProviders
|
||||
)
|
||||
new SeekableZipFilePart(headerFactory.NotNull(), deh, s),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
break;
|
||||
@@ -77,7 +73,7 @@ public partial class ZipArchive
|
||||
|
||||
protected override async ValueTask SaveToAsync(
|
||||
Stream stream,
|
||||
IWriterOptions options,
|
||||
ZipWriterOptions options,
|
||||
IAsyncEnumerable<ZipArchiveEntry> oldEntries,
|
||||
IEnumerable<ZipArchiveEntry> newEntries,
|
||||
CancellationToken cancellationToken = default
|
||||
|
||||
@@ -9,22 +9,29 @@ using SharpCompress.Common.Zip;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Writers.Zip;
|
||||
|
||||
namespace SharpCompress.Archives.Zip;
|
||||
|
||||
public partial class ZipArchive
|
||||
#if NET8_0_OR_GREATER
|
||||
: IWritableArchiveOpenable,
|
||||
IMultiArchiveOpenable<IWritableArchive, IWritableAsyncArchive>
|
||||
: IWritableArchiveOpenable<ZipWriterOptions>,
|
||||
IMultiArchiveOpenable<
|
||||
IWritableArchive<ZipWriterOptions>,
|
||||
IWritableAsyncArchive<ZipWriterOptions>
|
||||
>
|
||||
#endif
|
||||
{
|
||||
public static IWritableArchive OpenArchive(string filePath, ReaderOptions? readerOptions = null)
|
||||
public static IWritableArchive<ZipWriterOptions> OpenArchive(
|
||||
string filePath,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
filePath.NotNullOrEmpty(nameof(filePath));
|
||||
return OpenArchive(new FileInfo(filePath), readerOptions);
|
||||
}
|
||||
|
||||
public static IWritableArchive OpenArchive(
|
||||
public static IWritableArchive<ZipWriterOptions> OpenArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
@@ -39,7 +46,7 @@ public partial class ZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IWritableArchive OpenArchive(
|
||||
public static IWritableArchive<ZipWriterOptions> OpenArchive(
|
||||
IEnumerable<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
@@ -55,7 +62,7 @@ public partial class ZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IWritableArchive OpenArchive(
|
||||
public static IWritableArchive<ZipWriterOptions> OpenArchive(
|
||||
IEnumerable<Stream> streams,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
@@ -71,7 +78,10 @@ public partial class ZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IWritableArchive OpenArchive(Stream stream, ReaderOptions? readerOptions = null)
|
||||
public static IWritableArchive<ZipWriterOptions> OpenArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
stream.NotNull(nameof(stream));
|
||||
|
||||
@@ -85,55 +95,30 @@ public partial class ZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IWritableAsyncArchive)OpenArchive(path, readerOptions);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(path, readerOptions);
|
||||
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IWritableAsyncArchive)OpenArchive(stream, readerOptions);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(stream, readerOptions);
|
||||
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(fileInfo, readerOptions);
|
||||
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IWritableAsyncArchive)OpenArchive(streams, readerOptions);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(streams, readerOptions);
|
||||
|
||||
public static IWritableAsyncArchive OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(fileInfos, readerOptions);
|
||||
|
||||
public static bool IsZipFile(string filePath, string? password = null) =>
|
||||
IsZipFile(new FileInfo(filePath), password);
|
||||
@@ -218,7 +203,8 @@ public partial class ZipArchive
|
||||
var header = await headerFactory
|
||||
.ReadStreamHeaderAsync(stream)
|
||||
.Where(x => x.ZipHeaderType != ZipHeaderType.Split)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (header is null)
|
||||
{
|
||||
return false;
|
||||
@@ -235,9 +221,9 @@ public partial class ZipArchive
|
||||
}
|
||||
}
|
||||
|
||||
public static IWritableArchive CreateArchive() => new ZipArchive();
|
||||
public static IWritableArchive<ZipWriterOptions> CreateArchive() => new ZipArchive();
|
||||
|
||||
public static IWritableAsyncArchive CreateAsyncArchive() => new ZipArchive();
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> CreateAsyncArchive() => new ZipArchive();
|
||||
|
||||
public static async ValueTask<bool> IsZipMultiAsync(
|
||||
Stream stream,
|
||||
@@ -261,6 +247,7 @@ public partial class ZipArchive
|
||||
await foreach (
|
||||
var h in z.ReadSeekableHeaderAsync(stream)
|
||||
.WithCancellation(cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
x = h;
|
||||
|
||||
@@ -17,7 +17,8 @@ using SharpCompress.Writers.Zip;
|
||||
|
||||
namespace SharpCompress.Archives.Zip;
|
||||
|
||||
public partial class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
|
||||
public partial class ZipArchive
|
||||
: AbstractWritableArchive<ZipArchiveEntry, ZipVolume, ZipWriterOptions>
|
||||
{
|
||||
private readonly SeekableZipHeaderFactory? headerFactory;
|
||||
|
||||
@@ -95,12 +96,8 @@ public partial class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVo
|
||||
|
||||
yield return new ZipArchiveEntry(
|
||||
this,
|
||||
new SeekableZipFilePart(
|
||||
headerFactory.NotNull(),
|
||||
deh,
|
||||
s,
|
||||
ReaderOptions.CompressionProviders
|
||||
)
|
||||
new SeekableZipFilePart(headerFactory.NotNull(), deh, s),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
break;
|
||||
@@ -115,11 +112,12 @@ public partial class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVo
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveTo(Stream stream) => SaveTo(stream, new WriterOptions(CompressionType.Deflate));
|
||||
public void SaveTo(Stream stream) =>
|
||||
SaveTo(stream, new ZipWriterOptions(CompressionType.Deflate));
|
||||
|
||||
protected override void SaveTo(
|
||||
Stream stream,
|
||||
IWriterOptions options,
|
||||
ZipWriterOptions options,
|
||||
IEnumerable<ZipArchiveEntry> oldEntries,
|
||||
IEnumerable<ZipArchiveEntry> newEntries
|
||||
)
|
||||
|
||||
@@ -15,7 +15,9 @@ public partial class ZipArchiveEntry
|
||||
var part = Parts.Single();
|
||||
if (part is SeekableZipFilePart seekablePart)
|
||||
{
|
||||
return (await seekablePart.GetCompressedStreamAsync(cancellationToken)).NotNull();
|
||||
return (
|
||||
await seekablePart.GetCompressedStreamAsync(cancellationToken).ConfigureAwait(false)
|
||||
).NotNull();
|
||||
}
|
||||
return OpenEntryStream();
|
||||
}
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Zip;
|
||||
|
||||
namespace SharpCompress.Archives.Zip;
|
||||
|
||||
public partial class ZipArchiveEntry : ZipEntry, IArchiveEntry
|
||||
{
|
||||
internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart? part)
|
||||
: base(part) => Archive = archive;
|
||||
internal ZipArchiveEntry(
|
||||
ZipArchive archive,
|
||||
SeekableZipFilePart? part,
|
||||
IReaderOptions readerOptions
|
||||
)
|
||||
: base(part, readerOptions) => Archive = archive;
|
||||
|
||||
public virtual Stream OpenEntryStream() => Parts.Single().GetCompressedStream().NotNull();
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry
|
||||
DateTime? lastModified,
|
||||
bool closeStream
|
||||
)
|
||||
: base(archive, null)
|
||||
: base(archive, null, archive.ReaderOptions)
|
||||
{
|
||||
this.stream = stream;
|
||||
Key = path;
|
||||
@@ -36,7 +36,7 @@ internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry
|
||||
string directoryPath,
|
||||
DateTime? lastModified
|
||||
)
|
||||
: base(archive, null)
|
||||
: base(archive, null, archive.ReaderOptions)
|
||||
{
|
||||
stream = null;
|
||||
Key = directoryPath;
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.Ace.Headers;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
namespace SharpCompress.Common.Ace;
|
||||
|
||||
@@ -12,7 +13,8 @@ public class AceEntry : Entry
|
||||
{
|
||||
private readonly AceFilePart _filePart;
|
||||
|
||||
internal AceEntry(AceFilePart filePart)
|
||||
internal AceEntry(AceFilePart filePart, IReaderOptions readerOptions)
|
||||
: base(readerOptions)
|
||||
{
|
||||
_filePart = filePart;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public sealed partial class AceFileHeader
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var headerData = await ReadHeaderAsync(stream, cancellationToken);
|
||||
var headerData = await ReadHeaderAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
if (headerData.Length == 0)
|
||||
{
|
||||
return null;
|
||||
|
||||
@@ -19,7 +19,9 @@ public abstract partial class AceHeader
|
||||
{
|
||||
// Read header CRC (2 bytes) and header size (2 bytes)
|
||||
var headerBytes = new byte[4];
|
||||
if (!await stream.ReadFullyAsync(headerBytes, 0, 4, cancellationToken))
|
||||
if (
|
||||
!await stream.ReadFullyAsync(headerBytes, 0, 4, cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
return Array.Empty<byte>();
|
||||
}
|
||||
@@ -33,7 +35,11 @@ public abstract partial class AceHeader
|
||||
|
||||
// Read the header data
|
||||
var body = new byte[HeaderSize];
|
||||
if (!await stream.ReadFullyAsync(body, 0, HeaderSize, cancellationToken))
|
||||
if (
|
||||
!await stream
|
||||
.ReadFullyAsync(body, 0, HeaderSize, cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
return Array.Empty<byte>();
|
||||
}
|
||||
@@ -59,7 +65,7 @@ public abstract partial class AceHeader
|
||||
)
|
||||
{
|
||||
var bytes = new byte[14];
|
||||
if (!await stream.ReadFullyAsync(bytes, 0, 14, cancellationToken))
|
||||
if (!await stream.ReadFullyAsync(bytes, 0, 14, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public sealed partial class AceMainHeader
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var headerData = await ReadHeaderAsync(stream, cancellationToken);
|
||||
var headerData = await ReadHeaderAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
if (headerData.Length == 0)
|
||||
{
|
||||
return null;
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.GZip;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Tar;
|
||||
|
||||
namespace SharpCompress.Common.Arc;
|
||||
@@ -13,7 +14,8 @@ public class ArcEntry : Entry
|
||||
{
|
||||
private readonly ArcFilePart? _filePart;
|
||||
|
||||
internal ArcEntry(ArcFilePart? filePart)
|
||||
internal ArcEntry(ArcFilePart? filePart, IReaderOptions readerOptions)
|
||||
: base(readerOptions)
|
||||
{
|
||||
_filePart = filePart;
|
||||
}
|
||||
|
||||
@@ -41,8 +41,9 @@ public class ArcEntryHeader
|
||||
{
|
||||
byte[] headerBytes = new byte[29];
|
||||
if (
|
||||
await stream.ReadAsync(headerBytes, 0, headerBytes.Length, cancellationToken)
|
||||
!= headerBytes.Length
|
||||
await stream
|
||||
.ReadAsync(headerBytes, 0, headerBytes.Length, cancellationToken)
|
||||
.ConfigureAwait(false) != headerBytes.Length
|
||||
)
|
||||
{
|
||||
return null;
|
||||
|
||||
@@ -31,11 +31,9 @@ public partial class ArcFilePart
|
||||
compressedStream = new RunLength90Stream(_stream, (int)Header.CompressedSize);
|
||||
break;
|
||||
case CompressionType.Squeezed:
|
||||
compressedStream = await SqueezeStream.CreateAsync(
|
||||
_stream,
|
||||
(int)Header.CompressedSize,
|
||||
cancellationToken
|
||||
);
|
||||
compressedStream = await SqueezeStream
|
||||
.CreateAsync(_stream, (int)Header.CompressedSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
break;
|
||||
case CompressionType.Crunched:
|
||||
if (Header.OriginalSize > 128 * 1024)
|
||||
|
||||
@@ -10,4 +10,5 @@ public enum ArchiveType
|
||||
Arc,
|
||||
Arj,
|
||||
Ace,
|
||||
Lzw,
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.Arc;
|
||||
using SharpCompress.Common.Arj.Headers;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
namespace SharpCompress.Common.Arj;
|
||||
|
||||
@@ -12,7 +13,8 @@ public class ArjEntry : Entry
|
||||
{
|
||||
private readonly ArjFilePart _filePart;
|
||||
|
||||
internal ArjEntry(ArjFilePart filePart)
|
||||
internal ArjEntry(ArjFilePart filePart, IReaderOptions readerOptions)
|
||||
: base(readerOptions)
|
||||
{
|
||||
_filePart = filePart;
|
||||
}
|
||||
@@ -41,9 +43,9 @@ public class ArjEntry : Entry
|
||||
|
||||
public override DateTime? LastModifiedTime => _filePart.Header.DateTimeModified.DateTime;
|
||||
|
||||
public override DateTime? CreatedTime => _filePart.Header.DateTimeCreated.DateTime;
|
||||
public override DateTime? CreatedTime => _filePart.Header.DateTimeCreated?.DateTime;
|
||||
|
||||
public override DateTime? LastAccessedTime => _filePart.Header.DateTimeAccessed.DateTime;
|
||||
public override DateTime? LastAccessedTime => _filePart.Header.DateTimeAccessed?.DateTime;
|
||||
|
||||
public override DateTime? ArchivedTime => null;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ public abstract partial class ArjHeader
|
||||
{
|
||||
// check for magic bytes
|
||||
var magic = new byte[2];
|
||||
if (await stream.ReadAsync(magic, 0, 2, cancellationToken) != 2)
|
||||
if (await stream.ReadAsync(magic, 0, 2, cancellationToken).ConfigureAwait(false) != 2)
|
||||
{
|
||||
return Array.Empty<byte>();
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public abstract partial class ArjHeader
|
||||
|
||||
// read header_size
|
||||
byte[] headerBytes = new byte[2];
|
||||
await stream.ReadAsync(headerBytes, 0, 2, cancellationToken);
|
||||
await stream.ReadAsync(headerBytes, 0, 2, cancellationToken).ConfigureAwait(false);
|
||||
var headerSize = (ushort)(headerBytes[0] | headerBytes[1] << 8);
|
||||
if (headerSize < 1)
|
||||
{
|
||||
@@ -41,14 +41,16 @@ public abstract partial class ArjHeader
|
||||
}
|
||||
|
||||
var body = new byte[headerSize];
|
||||
var read = await stream.ReadAsync(body, 0, headerSize, cancellationToken);
|
||||
var read = await stream
|
||||
.ReadAsync(body, 0, headerSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (read < headerSize)
|
||||
{
|
||||
return Array.Empty<byte>();
|
||||
}
|
||||
|
||||
byte[] crc = new byte[4];
|
||||
read = await stream.ReadAsync(crc, 0, 4, cancellationToken);
|
||||
await stream.ReadFullyAsync(crc, 0, 4, cancellationToken).ConfigureAwait(false);
|
||||
var checksum = Crc32Stream.Compute(body);
|
||||
// Compute the hash value
|
||||
if (checksum != BitConverter.ToUInt32(crc, 0))
|
||||
@@ -68,7 +70,9 @@ public abstract partial class ArjHeader
|
||||
|
||||
while (true)
|
||||
{
|
||||
int bytesRead = await reader.ReadAsync(buffer, 0, 2, cancellationToken);
|
||||
int bytesRead = await reader
|
||||
.ReadAsync(buffer, 0, 2, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (bytesRead < 2)
|
||||
{
|
||||
throw new EndOfStreamException(
|
||||
@@ -83,7 +87,9 @@ public abstract partial class ArjHeader
|
||||
}
|
||||
|
||||
byte[] header = new byte[extHeaderSize];
|
||||
bytesRead = await reader.ReadAsync(header, 0, extHeaderSize, cancellationToken);
|
||||
bytesRead = await reader
|
||||
.ReadAsync(header, 0, extHeaderSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (bytesRead < extHeaderSize)
|
||||
{
|
||||
throw new EndOfStreamException(
|
||||
@@ -92,7 +98,9 @@ public abstract partial class ArjHeader
|
||||
}
|
||||
|
||||
byte[] crcextended = new byte[4];
|
||||
bytesRead = await reader.ReadAsync(crcextended, 0, 4, cancellationToken);
|
||||
bytesRead = await reader
|
||||
.ReadAsync(crcextended, 0, 4, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (bytesRead < 4)
|
||||
{
|
||||
throw new EndOfStreamException(
|
||||
@@ -122,7 +130,7 @@ public abstract partial class ArjHeader
|
||||
)
|
||||
{
|
||||
var bytes = new byte[2];
|
||||
if (await stream.ReadAsync(bytes, 0, 2, cancellationToken) != 2)
|
||||
if (await stream.ReadAsync(bytes, 0, 2, cancellationToken).ConfigureAwait(false) != 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ public partial class ArjLocalHeader
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var body = await ReadHeaderAsync(stream, cancellationToken);
|
||||
var body = await ReadHeaderAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
if (body.Length > 0)
|
||||
{
|
||||
await ReadExtendedHeadersAsync(stream, cancellationToken);
|
||||
await ReadExtendedHeadersAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
var header = LoadFrom(body);
|
||||
header.DataStartPosition = stream.Position;
|
||||
return header;
|
||||
|
||||
@@ -27,8 +27,8 @@ public partial class ArjLocalHeader : ArjHeader
|
||||
public byte FirstChapter { get; set; }
|
||||
public byte LastChapter { get; set; }
|
||||
public long ExtendedFilePosition { get; set; }
|
||||
public DosDateTime DateTimeAccessed { get; set; } = new DosDateTime(0);
|
||||
public DosDateTime DateTimeCreated { get; set; } = new DosDateTime(0);
|
||||
public DosDateTime? DateTimeAccessed { get; set; }
|
||||
public DosDateTime? DateTimeCreated { get; set; }
|
||||
public long OriginalSizeEvenForVolumes { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Comment { get; set; } = string.Empty;
|
||||
@@ -119,11 +119,9 @@ public partial class ArjLocalHeader : ArjHeader
|
||||
if (headerSize >= R9HdrSize)
|
||||
{
|
||||
rawTimestamp = ReadInt32();
|
||||
DateTimeAccessed =
|
||||
rawTimestamp != 0 ? new DosDateTime(rawTimestamp) : new DosDateTime(0);
|
||||
DateTimeAccessed = rawTimestamp != 0 ? new DosDateTime(rawTimestamp) : null;
|
||||
rawTimestamp = ReadInt32();
|
||||
DateTimeCreated =
|
||||
rawTimestamp != 0 ? new DosDateTime(rawTimestamp) : new DosDateTime(0);
|
||||
DateTimeCreated = rawTimestamp != 0 ? new DosDateTime(rawTimestamp) : null;
|
||||
OriginalSizeEvenForVolumes = ReadInt32();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ public partial class ArjMainHeader
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var body = await ReadHeaderAsync(stream, cancellationToken);
|
||||
await ReadExtendedHeadersAsync(stream, cancellationToken);
|
||||
var body = await ReadHeaderAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
await ReadExtendedHeadersAsync(stream, cancellationToken).ConfigureAwait(false);
|
||||
return LoadFrom(body);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
namespace SharpCompress.Common;
|
||||
|
||||
@@ -87,4 +88,14 @@ public abstract class Entry : IEntry
|
||||
/// Entry file attribute.
|
||||
/// </summary>
|
||||
public virtual int? Attrib => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// The options used when opening this entry's source (reader or archive).
|
||||
/// </summary>
|
||||
public IReaderOptions Options { get; protected set; }
|
||||
|
||||
protected Entry(IReaderOptions readerOptions)
|
||||
{
|
||||
Options = readerOptions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common;
|
||||
|
||||
@@ -10,8 +11,7 @@ internal static partial class ExtractionMethods
|
||||
public static async ValueTask WriteEntryToDirectoryAsync(
|
||||
IEntry entry,
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options,
|
||||
Func<string, ExtractionOptions?, CancellationToken, ValueTask> writeAsync,
|
||||
Func<string, CancellationToken, ValueTask> writeAsync,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
@@ -34,11 +34,9 @@ internal static partial class ExtractionMethods
|
||||
);
|
||||
}
|
||||
|
||||
options ??= new ExtractionOptions() { Overwrite = true };
|
||||
|
||||
var file = Path.GetFileName(entry.Key.NotNull("Entry Key is null")).NotNull("File is null");
|
||||
file = Utility.ReplaceInvalidFileNameChars(file);
|
||||
if (options.ExtractFullPath)
|
||||
if (entry.Options.ExtractFullPath)
|
||||
{
|
||||
var folder = Path.GetDirectoryName(entry.Key.NotNull("Entry Key is null"))
|
||||
.NotNull("Directory is null");
|
||||
@@ -72,9 +70,9 @@ internal static partial class ExtractionMethods
|
||||
"Entry is trying to write a file outside of the destination directory."
|
||||
);
|
||||
}
|
||||
await writeAsync(destinationFileName, options, cancellationToken).ConfigureAwait(false);
|
||||
await writeAsync(destinationFileName, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else if (options.ExtractFullPath && !Directory.Exists(destinationFileName))
|
||||
else if (entry.Options.ExtractFullPath && !Directory.Exists(destinationFileName))
|
||||
{
|
||||
Directory.CreateDirectory(destinationFileName);
|
||||
}
|
||||
@@ -83,36 +81,34 @@ internal static partial class ExtractionMethods
|
||||
public static async ValueTask WriteEntryToFileAsync(
|
||||
IEntry entry,
|
||||
string destinationFileName,
|
||||
ExtractionOptions? options,
|
||||
Func<string, FileMode, CancellationToken, ValueTask> openAndWriteAsync,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (entry.LinkTarget != null)
|
||||
{
|
||||
if (options?.SymbolicLinkHandler is not null)
|
||||
if (entry.Options.SymbolicLinkHandler is not null)
|
||||
{
|
||||
options.SymbolicLinkHandler(destinationFileName, entry.LinkTarget);
|
||||
entry.Options.SymbolicLinkHandler(destinationFileName, entry.LinkTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExtractionOptions.DefaultSymbolicLinkHandler(destinationFileName, entry.LinkTarget);
|
||||
ReaderOptions.DefaultSymbolicLinkHandler(destinationFileName, entry.LinkTarget);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var fm = FileMode.Create;
|
||||
options ??= new ExtractionOptions() { Overwrite = true };
|
||||
|
||||
if (!options.Overwrite)
|
||||
if (!entry.Options.Overwrite)
|
||||
{
|
||||
fm = FileMode.CreateNew;
|
||||
}
|
||||
|
||||
await openAndWriteAsync(destinationFileName, fm, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
entry.PreserveExtractionOptions(destinationFileName, options);
|
||||
entry.PreserveExtractionOptions(destinationFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common;
|
||||
|
||||
@@ -23,8 +24,7 @@ internal static partial class ExtractionMethods
|
||||
public static void WriteEntryToDirectory(
|
||||
IEntry entry,
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options,
|
||||
Action<string, ExtractionOptions?> write
|
||||
Action<string> write
|
||||
)
|
||||
{
|
||||
string destinationFileName;
|
||||
@@ -46,11 +46,9 @@ internal static partial class ExtractionMethods
|
||||
);
|
||||
}
|
||||
|
||||
options ??= new ExtractionOptions() { Overwrite = true };
|
||||
|
||||
var file = Path.GetFileName(entry.Key.NotNull("Entry Key is null")).NotNull("File is null");
|
||||
file = Utility.ReplaceInvalidFileNameChars(file);
|
||||
if (options.ExtractFullPath)
|
||||
if (entry.Options.ExtractFullPath)
|
||||
{
|
||||
var folder = Path.GetDirectoryName(entry.Key.NotNull("Entry Key is null"))
|
||||
.NotNull("Directory is null");
|
||||
@@ -84,9 +82,9 @@ internal static partial class ExtractionMethods
|
||||
"Entry is trying to write a file outside of the destination directory."
|
||||
);
|
||||
}
|
||||
write(destinationFileName, options);
|
||||
write(destinationFileName);
|
||||
}
|
||||
else if (options.ExtractFullPath && !Directory.Exists(destinationFileName))
|
||||
else if (entry.Options.ExtractFullPath && !Directory.Exists(destinationFileName))
|
||||
{
|
||||
Directory.CreateDirectory(destinationFileName);
|
||||
}
|
||||
@@ -95,34 +93,32 @@ internal static partial class ExtractionMethods
|
||||
public static void WriteEntryToFile(
|
||||
IEntry entry,
|
||||
string destinationFileName,
|
||||
ExtractionOptions? options,
|
||||
Action<string, FileMode> openAndWrite
|
||||
)
|
||||
{
|
||||
if (entry.LinkTarget != null)
|
||||
{
|
||||
if (options?.SymbolicLinkHandler is not null)
|
||||
if (entry.Options.SymbolicLinkHandler is not null)
|
||||
{
|
||||
options.SymbolicLinkHandler(destinationFileName, entry.LinkTarget);
|
||||
entry.Options.SymbolicLinkHandler(destinationFileName, entry.LinkTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExtractionOptions.DefaultSymbolicLinkHandler(destinationFileName, entry.LinkTarget);
|
||||
ReaderOptions.DefaultSymbolicLinkHandler(destinationFileName, entry.LinkTarget);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var fm = FileMode.Create;
|
||||
options ??= new ExtractionOptions() { Overwrite = true };
|
||||
|
||||
if (!options.Overwrite)
|
||||
if (!entry.Options.Overwrite)
|
||||
{
|
||||
fm = FileMode.CreateNew;
|
||||
}
|
||||
|
||||
openAndWrite(destinationFileName, fm);
|
||||
entry.PreserveExtractionOptions(destinationFileName, options);
|
||||
entry.PreserveExtractionOptions(destinationFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace SharpCompress.Common;
|
||||
|
||||
/// <summary>
|
||||
/// Options for configuring extraction behavior when extracting archive entries.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is immutable. Use the <c>with</c> expression to create modified copies:
|
||||
/// <code>
|
||||
/// var options = new ExtractionOptions { Overwrite = false };
|
||||
/// options = options with { PreserveFileTime = true };
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
public sealed record ExtractionOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Overwrite target if it exists.
|
||||
/// <para><b>Breaking change:</b> Default changed from false to true in version 0.40.0.</para>
|
||||
/// </summary>
|
||||
public bool Overwrite { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Extract with internal directory structure.
|
||||
/// <para><b>Breaking change:</b> Default changed from false to true in version 0.40.0.</para>
|
||||
/// </summary>
|
||||
public bool ExtractFullPath { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Preserve file time.
|
||||
/// <para><b>Breaking change:</b> Default changed from false to true in version 0.40.0.</para>
|
||||
/// </summary>
|
||||
public bool PreserveFileTime { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Preserve windows file attributes.
|
||||
/// </summary>
|
||||
public bool PreserveAttributes { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Delegate for writing symbolic links to disk.
|
||||
/// The first parameter is the source path (where the symlink is created).
|
||||
/// The second parameter is the target path (what the symlink refers to).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <b>Breaking change:</b> Changed from field to init-only property in version 0.40.0.
|
||||
/// The default handler logs a warning message.
|
||||
/// </remarks>
|
||||
public Action<string, string>? SymbolicLinkHandler { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ExtractionOptions instance with default values.
|
||||
/// </summary>
|
||||
public ExtractionOptions() { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ExtractionOptions instance with the specified overwrite behavior.
|
||||
/// </summary>
|
||||
/// <param name="overwrite">Whether to overwrite existing files.</param>
|
||||
public ExtractionOptions(bool overwrite)
|
||||
{
|
||||
Overwrite = overwrite;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ExtractionOptions instance with the specified extraction path and overwrite behavior.
|
||||
/// </summary>
|
||||
/// <param name="extractFullPath">Whether to preserve directory structure.</param>
|
||||
/// <param name="overwrite">Whether to overwrite existing files.</param>
|
||||
public ExtractionOptions(bool extractFullPath, bool overwrite)
|
||||
{
|
||||
ExtractFullPath = extractFullPath;
|
||||
Overwrite = overwrite;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ExtractionOptions instance with the specified extraction path, overwrite behavior, and file time preservation.
|
||||
/// </summary>
|
||||
/// <param name="extractFullPath">Whether to preserve directory structure.</param>
|
||||
/// <param name="overwrite">Whether to overwrite existing files.</param>
|
||||
/// <param name="preserveFileTime">Whether to preserve file modification times.</param>
|
||||
public ExtractionOptions(bool extractFullPath, bool overwrite, bool preserveFileTime)
|
||||
{
|
||||
ExtractFullPath = extractFullPath;
|
||||
Overwrite = overwrite;
|
||||
PreserveFileTime = preserveFileTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an ExtractionOptions instance configured for safe extraction (no overwrite).
|
||||
/// </summary>
|
||||
public static ExtractionOptions SafeExtract => new(overwrite: false);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an ExtractionOptions instance configured for flat extraction (no directory structure).
|
||||
/// </summary>
|
||||
public static ExtractionOptions FlatExtract => new(extractFullPath: false, overwrite: true);
|
||||
|
||||
/// <summary>
|
||||
/// Default symbolic link handler that logs a warning message.
|
||||
/// </summary>
|
||||
public static void DefaultSymbolicLinkHandler(string sourcePath, string targetPath)
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"Could not write symlink {sourcePath} -> {targetPath}, for more information please see https://github.com/dotnet/runtime/issues/24271"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,8 @@ public partial class GZipEntry
|
||||
)
|
||||
{
|
||||
yield return new GZipEntry(
|
||||
await GZipFilePart.CreateAsync(
|
||||
stream,
|
||||
options.ArchiveEncoding,
|
||||
options.CompressionProviders
|
||||
)
|
||||
await GZipFilePart.CreateAsync(stream, options.ArchiveEncoding).ConfigureAwait(false),
|
||||
options
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common.GZip;
|
||||
@@ -9,7 +10,11 @@ public partial class GZipEntry : Entry
|
||||
{
|
||||
private readonly GZipFilePart? _filePart;
|
||||
|
||||
internal GZipEntry(GZipFilePart? filePart) => _filePart = filePart;
|
||||
internal GZipEntry(GZipFilePart? filePart, IReaderOptions readerOptions)
|
||||
: base(readerOptions)
|
||||
{
|
||||
_filePart = filePart;
|
||||
}
|
||||
|
||||
public override CompressionType CompressionType => CompressionType.GZip;
|
||||
|
||||
@@ -41,9 +46,7 @@ public partial class GZipEntry : Entry
|
||||
|
||||
internal static IEnumerable<GZipEntry> GetEntries(Stream stream, ReaderOptions options)
|
||||
{
|
||||
yield return new GZipEntry(
|
||||
GZipFilePart.Create(stream, options.ArchiveEncoding, options.CompressionProviders)
|
||||
);
|
||||
yield return new GZipEntry(GZipFilePart.Create(stream, options.ArchiveEncoding), options);
|
||||
}
|
||||
|
||||
// Async methods moved to GZipEntry.Async.cs
|
||||
|
||||
@@ -30,12 +30,12 @@ internal sealed partial class GZipFilePart
|
||||
{
|
||||
var part = new GZipFilePart(stream, archiveEncoding, compressionProviders);
|
||||
|
||||
await part.ReadAndValidateGzipHeaderAsync(cancellationToken);
|
||||
await part.ReadAndValidateGzipHeaderAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
var position = stream.Position;
|
||||
stream.Position = stream.Length - 8;
|
||||
await part.ReadTrailerAsync(cancellationToken);
|
||||
await part.ReadTrailerAsync(cancellationToken).ConfigureAwait(false);
|
||||
stream.Position = position;
|
||||
part.EntryStartPosition = position;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ internal sealed partial class GZipFilePart
|
||||
{
|
||||
// Read and potentially verify the GZIP trailer: CRC32 and size mod 2^32
|
||||
var trailer = new byte[8];
|
||||
_ = await _stream.ReadFullyAsync(trailer, 0, 8, cancellationToken);
|
||||
_ = await _stream.ReadFullyAsync(trailer, 0, 8, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
Crc = BinaryPrimitives.ReadUInt32LittleEndian(trailer);
|
||||
UncompressedSize = BinaryPrimitives.ReadUInt32LittleEndian(trailer.AsSpan().Slice(4));
|
||||
@@ -64,7 +64,7 @@ internal sealed partial class GZipFilePart
|
||||
{
|
||||
// read the header on the first read
|
||||
var header = new byte[10];
|
||||
var n = await _stream.ReadAsync(header, 0, 10, cancellationToken);
|
||||
var n = await _stream.ReadAsync(header, 0, 10, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// workitem 8501: handle edge case (decompress empty stream)
|
||||
if (n == 0)
|
||||
@@ -88,28 +88,29 @@ internal sealed partial class GZipFilePart
|
||||
{
|
||||
// read and discard extra field
|
||||
var lengthField = new byte[2];
|
||||
_ = await _stream.ReadAsync(lengthField, 0, 2, cancellationToken);
|
||||
_ = await _stream.ReadAsync(lengthField, 0, 2, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var extraLength = (short)(lengthField[0] + (lengthField[1] * 256));
|
||||
var extra = new byte[extraLength];
|
||||
|
||||
if (!await _stream.ReadFullyAsync(extra, cancellationToken))
|
||||
if (!await _stream.ReadFullyAsync(extra, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
throw new ZlibException("Unexpected end-of-file reading GZIP header.");
|
||||
}
|
||||
}
|
||||
if ((header[3] & 0x08) == 0x08)
|
||||
{
|
||||
_name = await ReadZeroTerminatedStringAsync(_stream, cancellationToken);
|
||||
_name = await ReadZeroTerminatedStringAsync(_stream, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
if ((header[3] & 0x10) == 0x010)
|
||||
{
|
||||
await ReadZeroTerminatedStringAsync(_stream, cancellationToken);
|
||||
await ReadZeroTerminatedStringAsync(_stream, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
if ((header[3] & 0x02) == 0x02)
|
||||
{
|
||||
var buf = new byte[1];
|
||||
_ = await _stream.ReadAsync(buf, 0, 1, cancellationToken); // CRC16, ignore
|
||||
_ = await _stream.ReadAsync(buf, 0, 1, cancellationToken).ConfigureAwait(false); // CRC16, ignore
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +125,7 @@ internal sealed partial class GZipFilePart
|
||||
do
|
||||
{
|
||||
// workitem 7740
|
||||
var n = await stream.ReadAsync(buf1, 0, 1, cancellationToken);
|
||||
var n = await stream.ReadAsync(buf1, 0, 1, cancellationToken).ConfigureAwait(false);
|
||||
if (n != 1)
|
||||
{
|
||||
throw new ZlibException("Unexpected EOF reading GZIP header.");
|
||||
|
||||
@@ -4,13 +4,9 @@ namespace SharpCompress.Common;
|
||||
|
||||
internal static class EntryExtensions
|
||||
{
|
||||
internal static void PreserveExtractionOptions(
|
||||
this IEntry entry,
|
||||
string destinationFileName,
|
||||
ExtractionOptions options
|
||||
)
|
||||
internal static void PreserveExtractionOptions(this IEntry entry, string destinationFileName)
|
||||
{
|
||||
if (options.PreserveFileTime || options.PreserveAttributes)
|
||||
if (entry.Options.PreserveFileTime || entry.Options.PreserveAttributes)
|
||||
{
|
||||
var nf = new FileInfo(destinationFileName);
|
||||
if (!nf.Exists)
|
||||
@@ -19,7 +15,7 @@ internal static class EntryExtensions
|
||||
}
|
||||
|
||||
// update file time to original packed time
|
||||
if (options.PreserveFileTime)
|
||||
if (entry.Options.PreserveFileTime)
|
||||
{
|
||||
if (entry.CreatedTime.HasValue)
|
||||
{
|
||||
@@ -37,7 +33,7 @@ internal static class EntryExtensions
|
||||
}
|
||||
}
|
||||
|
||||
if (options.PreserveAttributes)
|
||||
if (entry.Options.PreserveAttributes)
|
||||
{
|
||||
if (entry.Attrib.HasValue)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
namespace SharpCompress.Common;
|
||||
|
||||
@@ -21,4 +22,9 @@ public interface IEntry
|
||||
DateTime? LastModifiedTime { get; }
|
||||
long Size { get; }
|
||||
int? Attrib { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The options used when opening this entry's source (reader or archive).
|
||||
/// </summary>
|
||||
IReaderOptions Options { get; }
|
||||
}
|
||||
|
||||
22
src/SharpCompress/Common/Lzw/LzwEntry.Async.cs
Normal file
22
src/SharpCompress/Common/Lzw/LzwEntry.Async.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common.Lzw;
|
||||
|
||||
public partial class LzwEntry
|
||||
{
|
||||
internal static async IAsyncEnumerable<LzwEntry> GetEntriesAsync(
|
||||
Stream stream,
|
||||
ReaderOptions options,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
yield return new LzwEntry(
|
||||
await LzwFilePart.CreateAsync(stream, options.ArchiveEncoding, cancellationToken),
|
||||
options
|
||||
);
|
||||
}
|
||||
}
|
||||
53
src/SharpCompress/Common/Lzw/LzwEntry.cs
Normal file
53
src/SharpCompress/Common/Lzw/LzwEntry.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common.Lzw;
|
||||
|
||||
public partial class LzwEntry : Entry
|
||||
{
|
||||
private readonly LzwFilePart? _filePart;
|
||||
|
||||
internal LzwEntry(LzwFilePart? filePart, IReaderOptions readerOptions)
|
||||
: base(readerOptions)
|
||||
{
|
||||
_filePart = filePart;
|
||||
}
|
||||
|
||||
public override CompressionType CompressionType => CompressionType.Lzw;
|
||||
|
||||
public override long Crc => 0;
|
||||
|
||||
public override string? Key => _filePart?.FilePartName;
|
||||
|
||||
public override string? LinkTarget => null;
|
||||
|
||||
public override long CompressedSize => 0;
|
||||
|
||||
public override long Size => 0;
|
||||
|
||||
public override DateTime? LastModifiedTime => null;
|
||||
|
||||
public override DateTime? CreatedTime => null;
|
||||
|
||||
public override DateTime? LastAccessedTime => null;
|
||||
|
||||
public override DateTime? ArchivedTime => null;
|
||||
|
||||
public override bool IsEncrypted => false;
|
||||
|
||||
public override bool IsDirectory => false;
|
||||
|
||||
public override bool IsSplitAfter => false;
|
||||
|
||||
internal override IEnumerable<FilePart> Parts => _filePart.Empty();
|
||||
|
||||
internal static IEnumerable<LzwEntry> GetEntries(Stream stream, ReaderOptions options)
|
||||
{
|
||||
yield return new LzwEntry(LzwFilePart.Create(stream, options.ArchiveEncoding), options);
|
||||
}
|
||||
|
||||
// Async methods moved to LzwEntry.Async.cs
|
||||
}
|
||||
23
src/SharpCompress/Common/Lzw/LzwFilePart.Async.cs
Normal file
23
src/SharpCompress/Common/Lzw/LzwFilePart.Async.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Common.Lzw;
|
||||
|
||||
internal sealed partial class LzwFilePart
|
||||
{
|
||||
internal static async ValueTask<LzwFilePart> CreateAsync(
|
||||
Stream stream,
|
||||
IArchiveEncoding archiveEncoding,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var part = new LzwFilePart(stream, archiveEncoding);
|
||||
|
||||
// For non-seekable streams, we can't track position, so use 0 since the stream will be
|
||||
// read sequentially from its current position.
|
||||
part.EntryStartPosition = stream.CanSeek ? stream.Position : 0;
|
||||
return part;
|
||||
}
|
||||
}
|
||||
60
src/SharpCompress/Common/Lzw/LzwFilePart.cs
Normal file
60
src/SharpCompress/Common/Lzw/LzwFilePart.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Compressors.Lzw;
|
||||
|
||||
namespace SharpCompress.Common.Lzw;
|
||||
|
||||
internal sealed partial class LzwFilePart : FilePart
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
private readonly string? _name;
|
||||
|
||||
internal static LzwFilePart Create(Stream stream, IArchiveEncoding archiveEncoding)
|
||||
{
|
||||
var part = new LzwFilePart(stream, archiveEncoding);
|
||||
|
||||
// For non-seekable streams, we can't track position, so use 0 since the stream will be
|
||||
// read sequentially from its current position.
|
||||
part.EntryStartPosition = stream.CanSeek ? stream.Position : 0;
|
||||
return part;
|
||||
}
|
||||
|
||||
private LzwFilePart(Stream stream, IArchiveEncoding archiveEncoding)
|
||||
: base(archiveEncoding)
|
||||
{
|
||||
_stream = stream;
|
||||
_name = DeriveFileName(stream);
|
||||
}
|
||||
|
||||
internal long EntryStartPosition { get; private set; }
|
||||
|
||||
internal override string? FilePartName => _name;
|
||||
|
||||
internal override Stream GetCompressedStream() =>
|
||||
new LzwStream(_stream) { IsStreamOwner = false };
|
||||
|
||||
internal override Stream GetRawStream() => _stream;
|
||||
|
||||
private static string? DeriveFileName(Stream stream)
|
||||
{
|
||||
// Unwrap SharpCompressStream to get to the underlying FileStream
|
||||
var unwrappedStream = stream;
|
||||
if (stream is SharpCompress.IO.IStreamStack streamStack)
|
||||
{
|
||||
unwrappedStream = streamStack.BaseStream();
|
||||
}
|
||||
|
||||
// Try to derive filename from FileStream
|
||||
if (unwrappedStream is FileStream fileStream && !string.IsNullOrEmpty(fileStream.Name))
|
||||
{
|
||||
var fileName = Path.GetFileName(fileStream.Name);
|
||||
// Strip .Z extension if present
|
||||
if (fileName.EndsWith(".Z", System.StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return fileName.Substring(0, fileName.Length - 2);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
// Default name for non-file streams
|
||||
return "data";
|
||||
}
|
||||
}
|
||||
17
src/SharpCompress/Common/Lzw/LzwVolume.cs
Normal file
17
src/SharpCompress/Common/Lzw/LzwVolume.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common.Lzw;
|
||||
|
||||
public class LzwVolume : Volume
|
||||
{
|
||||
public LzwVolume(Stream stream, ReaderOptions? options, int index)
|
||||
: base(stream, options, index) { }
|
||||
|
||||
public LzwVolume(FileInfo fileInfo, ReaderOptions options)
|
||||
: base(fileInfo.OpenRead(), options with { LeaveStreamOpen = false }) { }
|
||||
|
||||
public override bool IsFirstVolume => true;
|
||||
|
||||
public override bool IsMultiVolume => false;
|
||||
}
|
||||
39
src/SharpCompress/Common/Options/IExtractionOptions.cs
Normal file
39
src/SharpCompress/Common/Options/IExtractionOptions.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
|
||||
namespace SharpCompress.Common.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Options for configuring extraction behavior when extracting archive entries to the filesystem.
|
||||
/// </summary>
|
||||
public interface IExtractionOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Overwrite target if it exists.
|
||||
/// <para><b>Breaking change:</b> Default changed from false to true in version 0.40.0.</para>
|
||||
/// </summary>
|
||||
bool Overwrite { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Extract with internal directory structure.
|
||||
/// <para><b>Breaking change:</b> Default changed from false to true in version 0.40.0.</para>
|
||||
/// </summary>
|
||||
bool ExtractFullPath { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Preserve file time.
|
||||
/// <para><b>Breaking change:</b> Default changed from false to true in version 0.40.0.</para>
|
||||
/// </summary>
|
||||
bool PreserveFileTime { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Preserve windows file attributes.
|
||||
/// </summary>
|
||||
bool PreserveAttributes { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Delegate for writing symbolic links to disk.
|
||||
/// The first parameter is the source path (where the symlink is created).
|
||||
/// The second parameter is the target path (what the symlink refers to).
|
||||
/// </summary>
|
||||
Action<string, string>? SymbolicLinkHandler { get; init; }
|
||||
}
|
||||
@@ -2,10 +2,11 @@ using SharpCompress.Compressors;
|
||||
|
||||
namespace SharpCompress.Common.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Options for configuring reader behavior when opening archives.
|
||||
/// </summary>
|
||||
public interface IReaderOptions : IStreamOptions, IEncodingOptions, IProgressOptions
|
||||
public interface IReaderOptions
|
||||
: IStreamOptions,
|
||||
IEncodingOptions,
|
||||
IProgressOptions,
|
||||
IExtractionOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Look for RarArchive (Check for self-extracting archives or cases where RarArchive isn't at the start of the file)
|
||||
|
||||
@@ -26,7 +26,9 @@ internal sealed class AsyncRarCryptoBinaryReader : AsyncRarCrcBinaryReader
|
||||
var binary = new AsyncRarCryptoBinaryReader(stream);
|
||||
if (salt == null)
|
||||
{
|
||||
salt = await binary.ReadBytesAsyncBase(EncryptionConstV5.SIZE_SALT30);
|
||||
salt = await binary
|
||||
.ReadBytesAsyncBase(EncryptionConstV5.SIZE_SALT30)
|
||||
.ConfigureAwait(false);
|
||||
binary._readCount += EncryptionConstV5.SIZE_SALT30;
|
||||
}
|
||||
binary._rijndael = new BlockTransformer(cryptKey.Transformer(salt));
|
||||
|
||||
@@ -27,6 +27,6 @@ internal sealed partial class ArchiveCryptHeader
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
CryptInfo = await Rar5CryptoInfo.CreateAsync(reader, false);
|
||||
CryptInfo = await Rar5CryptoInfo.CreateAsync(reader, false).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,7 +329,9 @@ internal partial class FileHeader
|
||||
|
||||
if (HasFlag(FileFlagsV4.SALT))
|
||||
{
|
||||
R4Salt = await reader.ReadBytesAsync(EncryptionConstV5.SIZE_SALT30, cancellationToken);
|
||||
R4Salt = await reader
|
||||
.ReadBytesAsync(EncryptionConstV5.SIZE_SALT30, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
if (HasFlag(FileFlagsV4.EXT_TIME))
|
||||
{
|
||||
|
||||
@@ -64,19 +64,19 @@ public partial class RarHeaderFactory
|
||||
|
||||
if (_isRar5 && _cryptInfo != null)
|
||||
{
|
||||
await _cryptInfo.ReadInitVAsync(new AsyncMarkingBinaryReader(stream));
|
||||
await _cryptInfo
|
||||
.ReadInitVAsync(new AsyncMarkingBinaryReader(stream))
|
||||
.ConfigureAwait(false);
|
||||
var _headerKey = new CryptKey5(Options.Password!, _cryptInfo);
|
||||
|
||||
reader = await AsyncRarCryptoBinaryReader.Create(
|
||||
stream,
|
||||
_headerKey,
|
||||
_cryptInfo.Salt
|
||||
);
|
||||
reader = await AsyncRarCryptoBinaryReader
|
||||
.Create(stream, _headerKey, _cryptInfo.Salt)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var key = new CryptKey3(Options.Password);
|
||||
reader = await AsyncRarCryptoBinaryReader.Create(stream, key);
|
||||
reader = await AsyncRarCryptoBinaryReader.Create(stream, key).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,47 +57,46 @@ internal class Rar5CryptoInfo
|
||||
)
|
||||
{
|
||||
var cryptoInfo = new Rar5CryptoInfo();
|
||||
var cryptVersion = await reader.ReadRarVIntUInt32Async(
|
||||
cancellationToken: CancellationToken.None
|
||||
);
|
||||
var cryptVersion = await reader
|
||||
.ReadRarVIntUInt32Async(cancellationToken: CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
if (cryptVersion > EncryptionConstV5.VERSION)
|
||||
{
|
||||
throw new CryptographicException($"Unsupported crypto version of {cryptVersion}");
|
||||
}
|
||||
var encryptionFlags = await reader.ReadRarVIntUInt32Async(
|
||||
cancellationToken: CancellationToken.None
|
||||
);
|
||||
var encryptionFlags = await reader
|
||||
.ReadRarVIntUInt32Async(cancellationToken: CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
cryptoInfo.UsePswCheck = FlagUtility.HasFlag(
|
||||
encryptionFlags,
|
||||
EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK
|
||||
);
|
||||
cryptoInfo.LG2Count = (int)
|
||||
await reader.ReadRarVIntUInt32Async(cancellationToken: CancellationToken.None);
|
||||
await reader
|
||||
.ReadRarVIntUInt32Async(cancellationToken: CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
if (cryptoInfo.LG2Count > EncryptionConstV5.CRYPT5_KDF_LG2_COUNT_MAX)
|
||||
{
|
||||
throw new CryptographicException($"Unsupported LG2 count of {cryptoInfo.LG2Count}.");
|
||||
}
|
||||
|
||||
cryptoInfo.Salt = await reader.ReadBytesAsync(
|
||||
EncryptionConstV5.SIZE_SALT50,
|
||||
CancellationToken.None
|
||||
);
|
||||
cryptoInfo.Salt = await reader
|
||||
.ReadBytesAsync(EncryptionConstV5.SIZE_SALT50, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (readInitV)
|
||||
{
|
||||
await cryptoInfo.ReadInitVAsync(reader);
|
||||
await cryptoInfo.ReadInitVAsync(reader).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (cryptoInfo.UsePswCheck)
|
||||
{
|
||||
cryptoInfo.PswCheck = await reader.ReadBytesAsync(
|
||||
EncryptionConstV5.SIZE_PSWCHECK,
|
||||
CancellationToken.None
|
||||
);
|
||||
var _pswCheckCsm = await reader.ReadBytesAsync(
|
||||
EncryptionConstV5.SIZE_PSWCHECK_CSUM,
|
||||
CancellationToken.None
|
||||
);
|
||||
cryptoInfo.PswCheck = await reader
|
||||
.ReadBytesAsync(EncryptionConstV5.SIZE_PSWCHECK, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
var _pswCheckCsm = await reader
|
||||
.ReadBytesAsync(EncryptionConstV5.SIZE_PSWCHECK_CSUM, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var sha = SHA256.Create();
|
||||
cryptoInfo.UsePswCheck = sha.ComputeHash(cryptoInfo.PswCheck)
|
||||
@@ -111,7 +110,9 @@ internal class Rar5CryptoInfo
|
||||
InitV = reader.ReadBytes(EncryptionConstV5.SIZE_INITV);
|
||||
|
||||
public async ValueTask ReadInitVAsync(AsyncMarkingBinaryReader reader) =>
|
||||
InitV = await reader.ReadBytesAsync(EncryptionConstV5.SIZE_INITV, CancellationToken.None);
|
||||
InitV = await reader
|
||||
.ReadBytesAsync(EncryptionConstV5.SIZE_INITV, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
public bool UsePswCheck = false;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
|
||||
namespace SharpCompress.Common.Rar;
|
||||
@@ -7,6 +8,9 @@ public abstract class RarEntry : Entry
|
||||
{
|
||||
internal abstract FileHeader FileHeader { get; }
|
||||
|
||||
protected RarEntry(IReaderOptions readerOptions)
|
||||
: base(readerOptions) { }
|
||||
|
||||
/// <summary>
|
||||
/// As the V2017 port isn't complete, add this check to use the legacy Rar code.
|
||||
/// </summary>
|
||||
|
||||
@@ -118,7 +118,8 @@ public abstract class RarVolume : Volume
|
||||
var buffer = new byte[fh.CompressedSize];
|
||||
await fh
|
||||
.PackedStream.NotNull()
|
||||
.ReadFullyAsync(buffer, cancellationToken);
|
||||
.ReadFullyAsync(buffer, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
Comment = Encoding.UTF8.GetString(buffer, 0, buffer.Length - 1);
|
||||
}
|
||||
}
|
||||
@@ -184,7 +185,7 @@ public abstract class RarVolume : Volume
|
||||
|
||||
public async ValueTask<bool> IsSolidArchiveAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await EnsureArchiveHeaderLoadedAsync(cancellationToken);
|
||||
await EnsureArchiveHeaderLoadedAsync(cancellationToken).ConfigureAwait(false);
|
||||
return ArchiveHeader?.IsSolid ?? false;
|
||||
}
|
||||
|
||||
@@ -248,7 +249,7 @@ public abstract class RarVolume : Volume
|
||||
}
|
||||
|
||||
// we only want to load the archive header to avoid overhead but have to do the nasty thing and reset the stream
|
||||
await GetVolumeFilePartsAsync(cancellationToken).FirstAsync();
|
||||
await GetVolumeFilePartsAsync(cancellationToken).FirstAsync().ConfigureAwait(false);
|
||||
Stream.Position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ internal sealed partial class ArchiveReader
|
||||
{
|
||||
// TODO: Check Signature!
|
||||
_header = new byte[0x20];
|
||||
await stream.ReadExactAsync(_header, 0, 0x20, cancellationToken);
|
||||
await stream.ReadExactAsync(_header, 0, 0x20, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (
|
||||
!lookForHeader
|
||||
@@ -107,7 +107,9 @@ internal sealed partial class ArchiveReader
|
||||
_stream.Seek(nextHeaderOffset, SeekOrigin.Current);
|
||||
|
||||
var header = new byte[nextHeaderSize];
|
||||
await _stream.ReadExactAsync(header, 0, header.Length, cancellationToken);
|
||||
await _stream
|
||||
.ReadExactAsync(header, 0, header.Length, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (Crc.Finish(Crc.Update(Crc.INIT_CRC, header, 0, header.Length)) != nextHeaderCrc)
|
||||
{
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip;
|
||||
|
||||
public class SevenZipEntry : Entry
|
||||
{
|
||||
internal SevenZipEntry(SevenZipFilePart filePart) => FilePart = filePart;
|
||||
internal SevenZipEntry(SevenZipFilePart filePart, IReaderOptions readerOptions)
|
||||
: base(readerOptions)
|
||||
{
|
||||
FilePart = filePart;
|
||||
}
|
||||
|
||||
internal SevenZipFilePart FilePart { get; }
|
||||
|
||||
|
||||
@@ -68,12 +68,9 @@ internal class SevenZipFilePart : FilePart
|
||||
{
|
||||
return Stream.Null;
|
||||
}
|
||||
var folderStream = await _database.GetFolderStreamAsync(
|
||||
_stream,
|
||||
Folder!,
|
||||
_database.PasswordProvider,
|
||||
cancellationToken
|
||||
);
|
||||
var folderStream = await _database
|
||||
.GetFolderStreamAsync(_stream, Folder!, _database.PasswordProvider, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var firstFileIndex = _database._folderStartFileIndex[_database._folders.IndexOf(Folder!)];
|
||||
var skipCount = Index - firstFileIndex;
|
||||
@@ -84,7 +81,7 @@ internal class SevenZipFilePart : FilePart
|
||||
}
|
||||
if (skipSize > 0)
|
||||
{
|
||||
await folderStream.SkipAsync(skipSize, cancellationToken);
|
||||
await folderStream.SkipAsync(skipSize, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
return new ReadOnlySubStream(folderStream, Header.Size, leaveOpen: false);
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@ internal sealed partial class TarHeader
|
||||
switch (WriteFormat)
|
||||
{
|
||||
case TarHeaderWriteFormat.GNU_TAR_LONG_LINK:
|
||||
await WriteGnuTarLongLinkAsync(output, cancellationToken);
|
||||
await WriteGnuTarLongLinkAsync(output, cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
case TarHeaderWriteFormat.USTAR:
|
||||
await WriteUstarAsync(output, cancellationToken);
|
||||
await WriteUstarAsync(output, cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("This should be impossible...");
|
||||
@@ -162,13 +162,13 @@ internal sealed partial class TarHeader
|
||||
|
||||
if (nameByteCount > 100)
|
||||
{
|
||||
await WriteLongFilenameHeaderAsync(output, cancellationToken);
|
||||
await WriteLongFilenameHeaderAsync(output, cancellationToken).ConfigureAwait(false);
|
||||
Name = ArchiveEncoding.Decode(
|
||||
ArchiveEncoding.Encode(Name.NotNull("Name is null")),
|
||||
0,
|
||||
100 - ArchiveEncoding.GetEncoding().GetMaxByteCount(1)
|
||||
);
|
||||
await WriteGnuTarLongLinkAsync(output, cancellationToken);
|
||||
await WriteGnuTarLongLinkAsync(output, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ internal sealed partial class TarHeader
|
||||
|
||||
do
|
||||
{
|
||||
buffer = await ReadBlockAsync(reader);
|
||||
buffer = await ReadBlockAsync(reader).ConfigureAwait(false);
|
||||
|
||||
if (buffer.Length == 0)
|
||||
{
|
||||
@@ -216,12 +216,12 @@ internal sealed partial class TarHeader
|
||||
// to apply to the header that follows them.
|
||||
if (entryType == EntryType.LongName)
|
||||
{
|
||||
longName = await ReadLongNameAsync(reader, buffer);
|
||||
longName = await ReadLongNameAsync(reader, buffer).ConfigureAwait(false);
|
||||
continue;
|
||||
}
|
||||
else if (entryType == EntryType.LongLink)
|
||||
{
|
||||
longLinkName = await ReadLongNameAsync(reader, buffer);
|
||||
longLinkName = await ReadLongNameAsync(reader, buffer).ConfigureAwait(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ internal sealed partial class TarHeader
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(BLOCK_SIZE);
|
||||
try
|
||||
{
|
||||
await reader.ReadBytesAsync(buffer, 0, BLOCK_SIZE);
|
||||
await reader.ReadBytesAsync(buffer, 0, BLOCK_SIZE).ConfigureAwait(false);
|
||||
|
||||
if (buffer.Length != 0 && buffer.Length < BLOCK_SIZE)
|
||||
{
|
||||
@@ -313,7 +313,7 @@ internal sealed partial class TarHeader
|
||||
var nameBytes = ArrayPool<byte>.Shared.Rent(nameLength);
|
||||
try
|
||||
{
|
||||
await reader.ReadBytesAsync(nameBytes, 0, nameLength);
|
||||
await reader.ReadBytesAsync(nameBytes, 0, nameLength).ConfigureAwait(false);
|
||||
var remainingBytesToRead = BLOCK_SIZE - (nameLength % BLOCK_SIZE);
|
||||
|
||||
// Read the rest of the block and discard the data
|
||||
@@ -322,7 +322,9 @@ internal sealed partial class TarHeader
|
||||
var remainingBytes = ArrayPool<byte>.Shared.Rent(remainingBytesToRead);
|
||||
try
|
||||
{
|
||||
await reader.ReadBytesAsync(remainingBytes, 0, remainingBytesToRead);
|
||||
await reader
|
||||
.ReadBytesAsync(remainingBytes, 0, remainingBytesToRead)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Common.Tar;
|
||||
@@ -10,7 +11,8 @@ public partial class TarEntry
|
||||
StreamingMode mode,
|
||||
Stream stream,
|
||||
CompressionType compressionType,
|
||||
IArchiveEncoding archiveEncoding
|
||||
IArchiveEncoding archiveEncoding,
|
||||
IReaderOptions readerOptions
|
||||
)
|
||||
{
|
||||
await foreach (
|
||||
@@ -21,11 +23,19 @@ public partial class TarEntry
|
||||
{
|
||||
if (mode == StreamingMode.Seekable)
|
||||
{
|
||||
yield return new TarEntry(new TarFilePart(header, stream), compressionType);
|
||||
yield return new TarEntry(
|
||||
new TarFilePart(header, stream),
|
||||
compressionType,
|
||||
readerOptions
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new TarEntry(new TarFilePart(header, null), compressionType);
|
||||
yield return new TarEntry(
|
||||
new TarFilePart(header, null),
|
||||
compressionType,
|
||||
readerOptions
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.IO;
|
||||
|
||||
@@ -10,7 +11,8 @@ public partial class TarEntry : Entry
|
||||
{
|
||||
private readonly TarFilePart? _filePart;
|
||||
|
||||
internal TarEntry(TarFilePart? filePart, CompressionType type)
|
||||
internal TarEntry(TarFilePart? filePart, CompressionType type, IReaderOptions readerOptions)
|
||||
: base(readerOptions)
|
||||
{
|
||||
_filePart = filePart;
|
||||
CompressionType = type;
|
||||
@@ -54,7 +56,8 @@ public partial class TarEntry : Entry
|
||||
StreamingMode mode,
|
||||
Stream stream,
|
||||
CompressionType compressionType,
|
||||
IArchiveEncoding archiveEncoding
|
||||
IArchiveEncoding archiveEncoding,
|
||||
IReaderOptions readerOptions
|
||||
)
|
||||
{
|
||||
foreach (var header in TarHeaderFactory.ReadHeader(mode, stream, archiveEncoding))
|
||||
@@ -63,11 +66,19 @@ public partial class TarEntry : Entry
|
||||
{
|
||||
if (mode == StreamingMode.Seekable)
|
||||
{
|
||||
yield return new TarEntry(new TarFilePart(header, stream), compressionType);
|
||||
yield return new TarEntry(
|
||||
new TarFilePart(header, stream),
|
||||
compressionType,
|
||||
readerOptions
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new TarEntry(new TarFilePart(header, null), compressionType);
|
||||
yield return new TarEntry(
|
||||
new TarFilePart(header, null),
|
||||
compressionType,
|
||||
readerOptions
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -25,7 +25,7 @@ internal static partial class TarHeaderFactory
|
||||
try
|
||||
{
|
||||
header = new TarHeader(archiveEncoding);
|
||||
if (!await header.ReadAsync(reader))
|
||||
if (!await header.ReadAsync(reader).ConfigureAwait(false))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@ internal partial class DirectoryEndHeader
|
||||
{
|
||||
internal override async ValueTask Read(AsyncBinaryReader reader)
|
||||
{
|
||||
VolumeNumber = await reader.ReadUInt16Async();
|
||||
FirstVolumeWithDirectory = await reader.ReadUInt16Async();
|
||||
TotalNumberOfEntriesInDisk = await reader.ReadUInt16Async();
|
||||
TotalNumberOfEntries = await reader.ReadUInt16Async();
|
||||
DirectorySize = await reader.ReadUInt32Async();
|
||||
DirectoryStartOffsetRelativeToDisk = await reader.ReadUInt32Async();
|
||||
CommentLength = await reader.ReadUInt16Async();
|
||||
VolumeNumber = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
FirstVolumeWithDirectory = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
TotalNumberOfEntriesInDisk = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
TotalNumberOfEntries = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
DirectorySize = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
DirectoryStartOffsetRelativeToDisk = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
CommentLength = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
Comment = new byte[CommentLength];
|
||||
await reader.ReadBytesAsync(Comment, 0, CommentLength);
|
||||
await reader.ReadBytesAsync(Comment, 0, CommentLength).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,28 +10,33 @@ internal partial class DirectoryEntryHeader
|
||||
{
|
||||
internal override async ValueTask Read(AsyncBinaryReader reader)
|
||||
{
|
||||
Version = await reader.ReadUInt16Async();
|
||||
VersionNeededToExtract = await reader.ReadUInt16Async();
|
||||
Flags = (HeaderFlags)await reader.ReadUInt16Async();
|
||||
CompressionMethod = (ZipCompressionMethod)await reader.ReadUInt16Async();
|
||||
OriginalLastModifiedTime = LastModifiedTime = await reader.ReadUInt16Async();
|
||||
OriginalLastModifiedDate = LastModifiedDate = await reader.ReadUInt16Async();
|
||||
Crc = await reader.ReadUInt32Async();
|
||||
CompressedSize = await reader.ReadUInt32Async();
|
||||
UncompressedSize = await reader.ReadUInt32Async();
|
||||
var nameLength = await reader.ReadUInt16Async();
|
||||
var extraLength = await reader.ReadUInt16Async();
|
||||
var commentLength = await reader.ReadUInt16Async();
|
||||
DiskNumberStart = await reader.ReadUInt16Async();
|
||||
InternalFileAttributes = await reader.ReadUInt16Async();
|
||||
ExternalFileAttributes = await reader.ReadUInt32Async();
|
||||
RelativeOffsetOfEntryHeader = await reader.ReadUInt32Async();
|
||||
Version = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
VersionNeededToExtract = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
Flags = (HeaderFlags)await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
CompressionMethod = (ZipCompressionMethod)
|
||||
await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
OriginalLastModifiedTime = LastModifiedTime = await reader
|
||||
.ReadUInt16Async()
|
||||
.ConfigureAwait(false);
|
||||
OriginalLastModifiedDate = LastModifiedDate = await reader
|
||||
.ReadUInt16Async()
|
||||
.ConfigureAwait(false);
|
||||
Crc = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
CompressedSize = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
UncompressedSize = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
var nameLength = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
var extraLength = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
var commentLength = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
DiskNumberStart = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
InternalFileAttributes = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
ExternalFileAttributes = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
RelativeOffsetOfEntryHeader = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
var name = new byte[nameLength];
|
||||
var extra = new byte[extraLength];
|
||||
var comment = new byte[commentLength];
|
||||
await reader.ReadBytesAsync(name, 0, nameLength);
|
||||
await reader.ReadBytesAsync(extra, 0, extraLength);
|
||||
await reader.ReadBytesAsync(comment, 0, commentLength);
|
||||
await reader.ReadBytesAsync(name, 0, nameLength).ConfigureAwait(false);
|
||||
await reader.ReadBytesAsync(extra, 0, extraLength).ConfigureAwait(false);
|
||||
await reader.ReadBytesAsync(comment, 0, commentLength).ConfigureAwait(false);
|
||||
|
||||
ProcessReadData(name, extra, comment);
|
||||
}
|
||||
|
||||
@@ -9,20 +9,25 @@ internal partial class LocalEntryHeader
|
||||
{
|
||||
internal override async ValueTask Read(AsyncBinaryReader reader)
|
||||
{
|
||||
Version = await reader.ReadUInt16Async();
|
||||
Flags = (HeaderFlags)await reader.ReadUInt16Async();
|
||||
CompressionMethod = (ZipCompressionMethod)await reader.ReadUInt16Async();
|
||||
OriginalLastModifiedTime = LastModifiedTime = await reader.ReadUInt16Async();
|
||||
OriginalLastModifiedDate = LastModifiedDate = await reader.ReadUInt16Async();
|
||||
Crc = await reader.ReadUInt32Async();
|
||||
CompressedSize = await reader.ReadUInt32Async();
|
||||
UncompressedSize = await reader.ReadUInt32Async();
|
||||
var nameLength = await reader.ReadUInt16Async();
|
||||
var extraLength = await reader.ReadUInt16Async();
|
||||
Version = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
Flags = (HeaderFlags)await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
CompressionMethod = (ZipCompressionMethod)
|
||||
await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
OriginalLastModifiedTime = LastModifiedTime = await reader
|
||||
.ReadUInt16Async()
|
||||
.ConfigureAwait(false);
|
||||
OriginalLastModifiedDate = LastModifiedDate = await reader
|
||||
.ReadUInt16Async()
|
||||
.ConfigureAwait(false);
|
||||
Crc = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
CompressedSize = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
UncompressedSize = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
var nameLength = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
var extraLength = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
var name = new byte[nameLength];
|
||||
var extra = new byte[extraLength];
|
||||
await reader.ReadBytesAsync(name, 0, nameLength);
|
||||
await reader.ReadBytesAsync(extra, 0, extraLength);
|
||||
await reader.ReadBytesAsync(name, 0, nameLength).ConfigureAwait(false);
|
||||
await reader.ReadBytesAsync(extra, 0, extraLength).ConfigureAwait(false);
|
||||
|
||||
ProcessReadData(name, extra);
|
||||
}
|
||||
|
||||
@@ -8,19 +8,20 @@ internal partial class Zip64DirectoryEndHeader
|
||||
{
|
||||
internal override async ValueTask Read(AsyncBinaryReader reader)
|
||||
{
|
||||
SizeOfDirectoryEndRecord = (long)await reader.ReadUInt64Async();
|
||||
VersionMadeBy = await reader.ReadUInt16Async();
|
||||
VersionNeededToExtract = await reader.ReadUInt16Async();
|
||||
VolumeNumber = await reader.ReadUInt32Async();
|
||||
FirstVolumeWithDirectory = await reader.ReadUInt32Async();
|
||||
TotalNumberOfEntriesInDisk = (long)await reader.ReadUInt64Async();
|
||||
TotalNumberOfEntries = (long)await reader.ReadUInt64Async();
|
||||
DirectorySize = (long)await reader.ReadUInt64Async();
|
||||
DirectoryStartOffsetRelativeToDisk = (long)await reader.ReadUInt64Async();
|
||||
SizeOfDirectoryEndRecord = (long)await reader.ReadUInt64Async().ConfigureAwait(false);
|
||||
VersionMadeBy = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
VersionNeededToExtract = await reader.ReadUInt16Async().ConfigureAwait(false);
|
||||
VolumeNumber = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
FirstVolumeWithDirectory = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
TotalNumberOfEntriesInDisk = (long)await reader.ReadUInt64Async().ConfigureAwait(false);
|
||||
TotalNumberOfEntries = (long)await reader.ReadUInt64Async().ConfigureAwait(false);
|
||||
DirectorySize = (long)await reader.ReadUInt64Async().ConfigureAwait(false);
|
||||
DirectoryStartOffsetRelativeToDisk = (long)
|
||||
await reader.ReadUInt64Async().ConfigureAwait(false);
|
||||
var size = (int)(
|
||||
SizeOfDirectoryEndRecord - SIZE_OF_FIXED_HEADER_DATA_EXCEPT_SIGNATURE_AND_SIZE_FIELDS
|
||||
);
|
||||
DataSector = new byte[size];
|
||||
await reader.ReadBytesAsync(DataSector, 0, size);
|
||||
await reader.ReadBytesAsync(DataSector, 0, size).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,9 @@ internal partial class Zip64DirectoryEndLocatorHeader
|
||||
{
|
||||
internal override async ValueTask Read(AsyncBinaryReader reader)
|
||||
{
|
||||
FirstVolumeWithDirectory = await reader.ReadUInt32Async();
|
||||
RelativeOffsetOfTheEndOfDirectoryRecord = (long)await reader.ReadUInt64Async();
|
||||
TotalNumberOfVolumes = await reader.ReadUInt32Async();
|
||||
FirstVolumeWithDirectory = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
RelativeOffsetOfTheEndOfDirectoryRecord = (long)
|
||||
await reader.ReadUInt64Async().ConfigureAwait(false);
|
||||
TotalNumberOfVolumes = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,12 +13,14 @@ internal partial class SeekableZipFilePart
|
||||
{
|
||||
if (!_isLocalHeaderLoaded)
|
||||
{
|
||||
await LoadLocalHeaderAsync(cancellationToken);
|
||||
await LoadLocalHeaderAsync(cancellationToken).ConfigureAwait(false);
|
||||
_isLocalHeaderLoaded = true;
|
||||
}
|
||||
return await base.GetCompressedStreamAsync(cancellationToken);
|
||||
return await base.GetCompressedStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async ValueTask LoadLocalHeaderAsync(CancellationToken cancellationToken = default) =>
|
||||
Header = await _headerFactory.GetLocalHeaderAsync(BaseStream, (DirectoryEntryHeader)Header);
|
||||
Header = await _headerFactory
|
||||
.GetLocalHeaderAsync(BaseStream, (DirectoryEntryHeader)Header)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ internal sealed partial class SeekableZipHeaderFactory
|
||||
using var reader = new AsyncBinaryReader(stream, leaveOpen: true);
|
||||
#endif
|
||||
|
||||
await SeekBackToHeaderAsync(stream, reader);
|
||||
await SeekBackToHeaderAsync(stream, reader).ConfigureAwait(false);
|
||||
|
||||
var eocd_location = stream.Position;
|
||||
var entry = new DirectoryEndHeader();
|
||||
await entry.Read(reader);
|
||||
await entry.Read(reader).ConfigureAwait(false);
|
||||
|
||||
if (entry.IsZip64)
|
||||
{
|
||||
@@ -30,24 +30,24 @@ internal sealed partial class SeekableZipHeaderFactory
|
||||
|
||||
// ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR should be before the EOCD
|
||||
stream.Seek(eocd_location - ZIP64_EOCD_LENGTH - 4, SeekOrigin.Begin);
|
||||
uint zip64_locator = await reader.ReadUInt32Async();
|
||||
uint zip64_locator = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
if (zip64_locator != ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR)
|
||||
{
|
||||
throw new ArchiveException("Failed to locate the Zip64 Directory Locator");
|
||||
}
|
||||
|
||||
var zip64Locator = new Zip64DirectoryEndLocatorHeader();
|
||||
await zip64Locator.Read(reader);
|
||||
await zip64Locator.Read(reader).ConfigureAwait(false);
|
||||
|
||||
stream.Seek(zip64Locator.RelativeOffsetOfTheEndOfDirectoryRecord, SeekOrigin.Begin);
|
||||
var zip64Signature = await reader.ReadUInt32Async();
|
||||
var zip64Signature = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
if (zip64Signature != ZIP64_END_OF_CENTRAL_DIRECTORY)
|
||||
{
|
||||
throw new ArchiveException("Failed to locate the Zip64 Header");
|
||||
}
|
||||
|
||||
var zip64Entry = new Zip64DirectoryEndHeader();
|
||||
await zip64Entry.Read(reader);
|
||||
await zip64Entry.Read(reader).ConfigureAwait(false);
|
||||
stream.Seek(zip64Entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin);
|
||||
}
|
||||
else
|
||||
@@ -59,8 +59,8 @@ internal sealed partial class SeekableZipHeaderFactory
|
||||
while (true)
|
||||
{
|
||||
stream.Position = position;
|
||||
var signature = await reader.ReadUInt32Async();
|
||||
var nextHeader = await ReadHeader(signature, reader, _zip64);
|
||||
var signature = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
var nextHeader = await ReadHeader(signature, reader, _zip64).ConfigureAwait(false);
|
||||
position = stream.Position;
|
||||
|
||||
if (nextHeader is null)
|
||||
@@ -101,7 +101,7 @@ internal sealed partial class SeekableZipHeaderFactory
|
||||
|
||||
try
|
||||
{
|
||||
await reader.ReadBytesAsync(seek, 0, len, default);
|
||||
await reader.ReadBytesAsync(seek, 0, len, default).ConfigureAwait(false);
|
||||
var memory = new Memory<byte>(seek, 0, len);
|
||||
var span = memory.Span;
|
||||
span.Reverse();
|
||||
@@ -137,8 +137,11 @@ internal sealed partial class SeekableZipHeaderFactory
|
||||
#else
|
||||
using var reader = new AsyncBinaryReader(stream, leaveOpen: true);
|
||||
#endif
|
||||
var signature = await reader.ReadUInt32Async();
|
||||
if (await ReadHeader(signature, reader, _zip64) is not LocalEntryHeader localEntryHeader)
|
||||
var signature = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
if (
|
||||
await ReadHeader(signature, reader, _zip64).ConfigureAwait(false)
|
||||
is not LocalEntryHeader localEntryHeader
|
||||
)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
|
||||
namespace SharpCompress.Common.Zip;
|
||||
@@ -9,7 +10,8 @@ public class ZipEntry : Entry
|
||||
{
|
||||
private readonly ZipFilePart? _filePart;
|
||||
|
||||
internal ZipEntry(ZipFilePart? filePart)
|
||||
internal ZipEntry(ZipFilePart? filePart, IReaderOptions readerOptions)
|
||||
: base(readerOptions)
|
||||
{
|
||||
if (filePart == null)
|
||||
{
|
||||
|
||||
@@ -148,53 +148,63 @@ internal abstract partial class ZipFilePart
|
||||
}
|
||||
case ZipCompressionMethod.Reduce1:
|
||||
{
|
||||
return await ReduceStream.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
1,
|
||||
cancellationToken
|
||||
);
|
||||
return await ReduceStream
|
||||
.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
1,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.Reduce2:
|
||||
{
|
||||
return await ReduceStream.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
2,
|
||||
cancellationToken
|
||||
);
|
||||
return await ReduceStream
|
||||
.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
2,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.Reduce3:
|
||||
{
|
||||
return await ReduceStream.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
3,
|
||||
cancellationToken
|
||||
);
|
||||
return await ReduceStream
|
||||
.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
3,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.Reduce4:
|
||||
{
|
||||
return await ReduceStream.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
4,
|
||||
cancellationToken
|
||||
);
|
||||
return await ReduceStream
|
||||
.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
4,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.Explode:
|
||||
{
|
||||
return await ExplodeStream.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
Header.Flags,
|
||||
cancellationToken
|
||||
);
|
||||
return await ExplodeStream
|
||||
.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
Header.Flags,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
case ZipCompressionMethod.Deflate:
|
||||
@@ -207,12 +217,14 @@ internal abstract partial class ZipFilePart
|
||||
}
|
||||
case ZipCompressionMethod.BZip2:
|
||||
{
|
||||
return await BZip2Stream.CreateAsync(
|
||||
stream,
|
||||
CompressionMode.Decompress,
|
||||
false,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
return await BZip2Stream
|
||||
.CreateAsync(
|
||||
stream,
|
||||
CompressionMode.Decompress,
|
||||
false,
|
||||
cancellationToken: cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.LZMA:
|
||||
{
|
||||
@@ -228,14 +240,16 @@ internal abstract partial class ZipFilePart
|
||||
await stream
|
||||
.ReadFullyAsync(props, 0, propsSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return await LzmaStream.CreateAsync(
|
||||
props,
|
||||
stream,
|
||||
Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1,
|
||||
FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
|
||||
? -1
|
||||
: Header.UncompressedSize
|
||||
);
|
||||
return await LzmaStream
|
||||
.CreateAsync(
|
||||
props,
|
||||
stream,
|
||||
Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1,
|
||||
FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
|
||||
? -1
|
||||
: Header.UncompressedSize
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.Xz:
|
||||
{
|
||||
@@ -284,11 +298,12 @@ internal abstract partial class ZipFilePart
|
||||
}
|
||||
|
||||
return await CreateDecompressionStreamAsync(
|
||||
stream,
|
||||
(ZipCompressionMethod)
|
||||
BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(5)),
|
||||
cancellationToken
|
||||
);
|
||||
stream,
|
||||
(ZipCompressionMethod)
|
||||
BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(5)),
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
default:
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ internal partial class ZipHeaderFactory
|
||||
case ENTRY_HEADER_BYTES:
|
||||
{
|
||||
var entryHeader = new LocalEntryHeader(_archiveEncoding);
|
||||
await entryHeader.Read(reader);
|
||||
await entryHeader.Read(reader).ConfigureAwait(false);
|
||||
await LoadHeaderAsync(entryHeader, reader.BaseStream).ConfigureAwait(false);
|
||||
|
||||
_lastEntryHeader = entryHeader;
|
||||
@@ -30,7 +30,7 @@ internal partial class ZipHeaderFactory
|
||||
case DIRECTORY_START_HEADER_BYTES:
|
||||
{
|
||||
var entry = new DirectoryEntryHeader(_archiveEncoding);
|
||||
await entry.Read(reader);
|
||||
await entry.Read(reader).ConfigureAwait(false);
|
||||
return entry;
|
||||
}
|
||||
case POST_DATA_DESCRIPTOR:
|
||||
@@ -43,17 +43,17 @@ internal partial class ZipHeaderFactory
|
||||
)
|
||||
)
|
||||
{
|
||||
_lastEntryHeader.Crc = await reader.ReadUInt32Async();
|
||||
_lastEntryHeader.Crc = await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
_lastEntryHeader.CompressedSize = zip64
|
||||
? (long)await reader.ReadUInt64Async()
|
||||
: await reader.ReadUInt32Async();
|
||||
? (long)await reader.ReadUInt64Async().ConfigureAwait(false)
|
||||
: await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
_lastEntryHeader.UncompressedSize = zip64
|
||||
? (long)await reader.ReadUInt64Async()
|
||||
: await reader.ReadUInt32Async();
|
||||
? (long)await reader.ReadUInt64Async().ConfigureAwait(false)
|
||||
: await reader.ReadUInt32Async().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await reader.SkipAsync(zip64 ? 20 : 12);
|
||||
await reader.SkipAsync(zip64 ? 20 : 12).ConfigureAwait(false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -62,7 +62,7 @@ internal partial class ZipHeaderFactory
|
||||
case DIRECTORY_END_HEADER_BYTES:
|
||||
{
|
||||
var entry = new DirectoryEndHeader();
|
||||
await entry.Read(reader);
|
||||
await entry.Read(reader).ConfigureAwait(false);
|
||||
return entry;
|
||||
}
|
||||
case SPLIT_ARCHIVE_HEADER_BYTES:
|
||||
@@ -72,13 +72,13 @@ internal partial class ZipHeaderFactory
|
||||
case ZIP64_END_OF_CENTRAL_DIRECTORY:
|
||||
{
|
||||
var entry = new Zip64DirectoryEndHeader();
|
||||
await entry.Read(reader);
|
||||
await entry.Read(reader).ConfigureAwait(false);
|
||||
return entry;
|
||||
}
|
||||
case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR:
|
||||
{
|
||||
var entry = new Zip64DirectoryEndLocatorHeader();
|
||||
await entry.Read(reader);
|
||||
await entry.Read(reader).ConfigureAwait(false);
|
||||
return entry;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -19,7 +19,9 @@ public static partial class ADCBase
|
||||
byte[] input,
|
||||
int bufferSize = 262144,
|
||||
CancellationToken cancellationToken = default
|
||||
) => await DecompressAsync(new MemoryStream(input), bufferSize, cancellationToken);
|
||||
) =>
|
||||
await DecompressAsync(new MemoryStream(input), bufferSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses a stream asynchronously that's compressed with ADC
|
||||
@@ -76,12 +78,9 @@ public static partial class ADCBase
|
||||
break;
|
||||
}
|
||||
|
||||
var readCount = await input.ReadAsync(
|
||||
buffer,
|
||||
outPosition,
|
||||
chunkSize,
|
||||
cancellationToken
|
||||
);
|
||||
var readCount = await input
|
||||
.ReadAsync(buffer, outPosition, chunkSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
outPosition += readCount;
|
||||
position += readCount + 1;
|
||||
break;
|
||||
|
||||
@@ -66,10 +66,9 @@ public sealed partial class ADCStream
|
||||
|
||||
if (_outBuffer is null)
|
||||
{
|
||||
var result = await ADCBase.DecompressAsync(
|
||||
_stream,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
var result = await ADCBase
|
||||
.DecompressAsync(_stream, cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
_outBuffer = result.Output;
|
||||
_outPosition = 0;
|
||||
}
|
||||
@@ -87,10 +86,9 @@ public sealed partial class ADCStream
|
||||
copied += piece;
|
||||
_position += piece;
|
||||
toCopy -= piece;
|
||||
var result = await ADCBase.DecompressAsync(
|
||||
_stream,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
var result = await ADCBase
|
||||
.DecompressAsync(_stream, cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
_outBuffer = result.Output;
|
||||
_outPosition = 0;
|
||||
if (result.BytesRead == 0 || _outBuffer is null || _outBuffer.Length == 0)
|
||||
|
||||
@@ -31,12 +31,9 @@ public sealed partial class BZip2Stream
|
||||
}
|
||||
else
|
||||
{
|
||||
bZip2Stream.stream = await CBZip2InputStream.CreateAsync(
|
||||
stream,
|
||||
decompressConcatenated,
|
||||
leaveOpen,
|
||||
cancellationToken
|
||||
);
|
||||
bZip2Stream.stream = await CBZip2InputStream
|
||||
.CreateAsync(stream, decompressConcatenated, leaveOpen, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return bZip2Stream;
|
||||
@@ -55,7 +52,9 @@ public sealed partial class BZip2Stream
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var buffer = new byte[2];
|
||||
var bytesRead = await stream.ReadAsync(buffer, 0, 2, cancellationToken);
|
||||
var bytesRead = await stream
|
||||
.ReadAsync(buffer, 0, 2, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (bytesRead < 2 || buffer[0] != 'B' || buffer[1] != 'Z')
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -800,14 +800,6 @@ internal partial class CBZip2InputStream
|
||||
return k;
|
||||
}
|
||||
|
||||
private async ValueTask BsSetStreamAsync(Stream f, CancellationToken cancellationToken)
|
||||
{
|
||||
bsStream = f;
|
||||
bsLive = 0;
|
||||
bsBuff = 0;
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async ValueTask<int> BsRAsync(int n, CancellationToken cancellationToken)
|
||||
{
|
||||
int v;
|
||||
@@ -818,7 +810,7 @@ internal partial class CBZip2InputStream
|
||||
var b = ArrayPool<byte>.Shared.Rent(1);
|
||||
try
|
||||
{
|
||||
await bsStream.ReadExactAsync(b, 0, 1, cancellationToken);
|
||||
await bsStream.ReadExactAsync(b, 0, 1, cancellationToken).ConfigureAwait(false);
|
||||
thech = (char)b[0];
|
||||
}
|
||||
catch (IOException)
|
||||
@@ -844,15 +836,15 @@ internal partial class CBZip2InputStream
|
||||
}
|
||||
|
||||
private async ValueTask<char> BsGetUCharAsync(CancellationToken cancellationToken) =>
|
||||
(char)await BsRAsync(8, cancellationToken);
|
||||
(char)await BsRAsync(8, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
private async ValueTask<int> BsGetIntVSAsync(
|
||||
int numBits,
|
||||
CancellationToken cancellationToken
|
||||
) => await BsRAsync(numBits, cancellationToken);
|
||||
) => await BsRAsync(numBits, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
private async ValueTask<int> BsGetInt32Async(CancellationToken cancellationToken) =>
|
||||
await BsGetintAsync(cancellationToken);
|
||||
await BsGetintAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
public static async ValueTask<CBZip2InputStream> CreateAsync(
|
||||
Stream zStream,
|
||||
@@ -864,10 +856,10 @@ internal partial class CBZip2InputStream
|
||||
var cbZip2InputStream = new CBZip2InputStream(decompressConcatenated, leaveOpen);
|
||||
cbZip2InputStream.ll8 = null;
|
||||
cbZip2InputStream.tt = null;
|
||||
await cbZip2InputStream.BsSetStreamAsync(zStream, cancellationToken);
|
||||
await cbZip2InputStream.InitializeAsync(true, cancellationToken);
|
||||
await cbZip2InputStream.InitBlockAsync(cancellationToken);
|
||||
await cbZip2InputStream.SetupBlockAsync(cancellationToken);
|
||||
cbZip2InputStream.BsSetStream(zStream);
|
||||
await cbZip2InputStream.InitializeAsync(true, cancellationToken).ConfigureAwait(false);
|
||||
await cbZip2InputStream.InitBlockAsync(cancellationToken).ConfigureAwait(false);
|
||||
await cbZip2InputStream.SetupBlockAsync(cancellationToken).ConfigureAwait(false);
|
||||
return cbZip2InputStream;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user