mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-10 05:31:29 +00:00
Compare commits
15 Commits
adam/make-
...
adam/clean
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e21631526b | ||
|
|
cf0ad9b323 | ||
|
|
938692ef33 | ||
|
|
84c49f152e | ||
|
|
04dd177f19 | ||
|
|
2e074e18d4 | ||
|
|
756cb7bd9d | ||
|
|
c37209618d | ||
|
|
c4a28e7cfb | ||
|
|
29197f2142 | ||
|
|
2a4081362e | ||
|
|
d5cab8172b | ||
|
|
4084b347d4 | ||
|
|
5437d9ff8c | ||
|
|
cc6e410be8 |
@@ -3,7 +3,7 @@
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"csharpier": {
|
||||
"version": "1.2.5",
|
||||
"version": "1.2.6",
|
||||
"commands": [
|
||||
"csharpier"
|
||||
],
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Writers;
|
||||
|
||||
namespace SharpCompress.Archives;
|
||||
@@ -111,7 +112,7 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
|
||||
|
||||
public async ValueTask SaveToAsync(
|
||||
Stream stream,
|
||||
WriterOptions options,
|
||||
IWriterOptions options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Writers;
|
||||
|
||||
@@ -174,7 +175,7 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void SaveTo(Stream stream, WriterOptions options)
|
||||
public void SaveTo(Stream stream, IWriterOptions options)
|
||||
{
|
||||
//reset streams of new entries
|
||||
newEntries.Cast<IWritableArchiveEntry>().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin));
|
||||
@@ -210,14 +211,14 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
|
||||
|
||||
protected abstract void SaveTo(
|
||||
Stream stream,
|
||||
WriterOptions options,
|
||||
IWriterOptions options,
|
||||
IEnumerable<TEntry> oldEntries,
|
||||
IEnumerable<TEntry> newEntries
|
||||
);
|
||||
|
||||
protected abstract ValueTask SaveToAsync(
|
||||
Stream stream,
|
||||
WriterOptions options,
|
||||
IWriterOptions options,
|
||||
IAsyncEnumerable<TEntry> oldEntries,
|
||||
IEnumerable<TEntry> newEntries,
|
||||
CancellationToken cancellationToken = default
|
||||
|
||||
@@ -94,11 +94,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)
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Threading;
|
||||
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;
|
||||
@@ -30,7 +31,7 @@ public partial class GZipArchive
|
||||
|
||||
protected override async ValueTask SaveToAsync(
|
||||
Stream stream,
|
||||
WriterOptions options,
|
||||
IWriterOptions options,
|
||||
IAsyncEnumerable<GZipArchiveEntry> oldEntries,
|
||||
IEnumerable<GZipArchiveEntry> newEntries,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -40,7 +41,10 @@ public partial class GZipArchive
|
||||
{
|
||||
throw new InvalidFormatException("Only one entry is allowed in a GZip Archive");
|
||||
}
|
||||
using var writer = new GZipWriter(stream, new GZipWriterOptions(options));
|
||||
using var writer = new GZipWriter(
|
||||
stream,
|
||||
options as GZipWriterOptions ?? new GZipWriterOptions(options)
|
||||
);
|
||||
await foreach (
|
||||
var entry in oldEntries.WithCancellation(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
@@ -80,7 +84,8 @@ public partial class GZipArchive
|
||||
var stream = (await volumes.SingleAsync()).Stream;
|
||||
yield return new GZipArchiveEntry(
|
||||
this,
|
||||
await GZipFilePart.CreateAsync(stream, ReaderOptions.ArchiveEncoding)
|
||||
await GZipFilePart.CreateAsync(stream, ReaderOptions.ArchiveEncoding),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading;
|
||||
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;
|
||||
@@ -58,7 +59,7 @@ public partial class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZi
|
||||
|
||||
protected override void SaveTo(
|
||||
Stream stream,
|
||||
WriterOptions options,
|
||||
IWriterOptions options,
|
||||
IEnumerable<GZipArchiveEntry> oldEntries,
|
||||
IEnumerable<GZipArchiveEntry> newEntries
|
||||
)
|
||||
@@ -67,7 +68,10 @@ public partial class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZi
|
||||
{
|
||||
throw new InvalidFormatException("Only one entry is allowed in a GZip Archive");
|
||||
}
|
||||
using var writer = new GZipWriter(stream, new GZipWriterOptions(options));
|
||||
using var writer = new GZipWriter(
|
||||
stream,
|
||||
options as GZipWriterOptions ?? new GZipWriterOptions(options)
|
||||
);
|
||||
foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory))
|
||||
{
|
||||
using var entryStream = entry.OpenEntryStream();
|
||||
@@ -84,7 +88,8 @@ public partial class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZi
|
||||
var stream = volumes.Single().Stream;
|
||||
yield return new GZipArchiveEntry(
|
||||
this,
|
||||
GZipFilePart.Create(stream, ReaderOptions.ArchiveEncoding)
|
||||
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
|
||||
|
||||
@@ -100,15 +100,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 +112,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 +127,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 +143,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(
|
||||
|
||||
@@ -17,12 +17,10 @@ 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
|
||||
)
|
||||
@@ -30,17 +28,14 @@ public static class IAsyncArchiveExtensions
|
||||
if (await archive.IsSolidAsync() || archive.Type == ArchiveType.SevenZip)
|
||||
{
|
||||
await using var reader = await archive.ExtractAllEntriesAsync();
|
||||
await reader.WriteAllToDirectoryAsync(
|
||||
destinationDirectory,
|
||||
options,
|
||||
cancellationToken
|
||||
);
|
||||
await reader
|
||||
.WriteAllToDirectoryAsync(destinationDirectory, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await archive.WriteToDirectoryAsyncInternal(
|
||||
destinationDirectory,
|
||||
options,
|
||||
progress,
|
||||
cancellationToken
|
||||
);
|
||||
@@ -49,7 +44,6 @@ public static class IAsyncArchiveExtensions
|
||||
|
||||
private async ValueTask WriteToDirectoryAsyncInternal(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options,
|
||||
IProgress<ProgressReport>? progress,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
@@ -79,7 +73,7 @@ public static class IAsyncArchiveExtensions
|
||||
}
|
||||
|
||||
await entry
|
||||
.WriteToDirectoryAsync(destinationDirectory, options, cancellationToken)
|
||||
.WriteToDirectoryAsync(destinationDirectory, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
bytesRead += entry.Size;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Writers;
|
||||
|
||||
namespace SharpCompress.Archives;
|
||||
@@ -30,7 +31,7 @@ public interface IWritableArchive : IArchive, IWritableArchiveCommon
|
||||
/// <summary>
|
||||
/// Saves the archive to the specified stream using the given writer options.
|
||||
/// </summary>
|
||||
void SaveTo(Stream stream, WriterOptions options);
|
||||
void SaveTo(Stream stream, IWriterOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the specified entry from the archive.
|
||||
@@ -45,7 +46,7 @@ public interface IWritableAsyncArchive : IAsyncArchive, IWritableArchiveCommon
|
||||
/// </summary>
|
||||
ValueTask SaveToAsync(
|
||||
Stream stream,
|
||||
WriterOptions options,
|
||||
IWriterOptions options,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Writers;
|
||||
|
||||
namespace SharpCompress.Archives;
|
||||
@@ -58,13 +59,16 @@ public static class IWritableArchiveExtensions
|
||||
);
|
||||
}
|
||||
|
||||
public void SaveTo(string filePath, WriterOptions? options = null) =>
|
||||
writableArchive.SaveTo(new FileInfo(filePath), options ?? new(CompressionType.Deflate));
|
||||
public void SaveTo(string filePath, IWriterOptions? options = null) =>
|
||||
writableArchive.SaveTo(
|
||||
new FileInfo(filePath),
|
||||
options ?? new WriterOptions(CompressionType.Deflate)
|
||||
);
|
||||
|
||||
public void SaveTo(FileInfo fileInfo, WriterOptions? options = null)
|
||||
public void SaveTo(FileInfo fileInfo, IWriterOptions? options = null)
|
||||
{
|
||||
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
|
||||
writableArchive.SaveTo(stream, options ?? new(CompressionType.Deflate));
|
||||
writableArchive.SaveTo(stream, options ?? new WriterOptions(CompressionType.Deflate));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Writers;
|
||||
|
||||
namespace SharpCompress.Archives;
|
||||
@@ -62,24 +63,28 @@ public static class IWritableAsyncArchiveExtensions
|
||||
|
||||
public ValueTask SaveToAsync(
|
||||
string filePath,
|
||||
WriterOptions? options = null,
|
||||
IWriterOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
writableArchive.SaveToAsync(
|
||||
new FileInfo(filePath),
|
||||
options ?? new(CompressionType.Deflate),
|
||||
options ?? new WriterOptions(CompressionType.Deflate),
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
public async ValueTask SaveToAsync(
|
||||
FileInfo fileInfo,
|
||||
WriterOptions? options = null,
|
||||
IWriterOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
|
||||
await writableArchive
|
||||
.SaveToAsync(stream, options ?? new(CompressionType.Deflate), cancellationToken)
|
||||
.SaveToAsync(
|
||||
stream,
|
||||
options ?? new WriterOptions(CompressionType.Deflate),
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,7 @@ internal class FileInfoRarArchiveVolume : RarVolume
|
||||
private static ReaderOptions FixOptions(ReaderOptions options)
|
||||
{
|
||||
//make sure we're closing streams with fileinfo
|
||||
options.LeaveStreamOpen = false;
|
||||
return options;
|
||||
return options with { LeaveStreamOpen = false };
|
||||
}
|
||||
|
||||
internal ReadOnlyCollection<RarFilePart> FileParts { get; }
|
||||
|
||||
@@ -23,6 +23,7 @@ public partial class RarArchiveEntry : RarEntry, IArchiveEntry
|
||||
IEnumerable<RarFilePart> parts,
|
||||
ReaderOptions readerOptions
|
||||
)
|
||||
: base(readerOptions)
|
||||
{
|
||||
this.parts = parts.ToList();
|
||||
this.archive = archive;
|
||||
|
||||
@@ -49,7 +49,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))
|
||||
|
||||
@@ -55,7 +55,8 @@ public partial class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, Sev
|
||||
i,
|
||||
file,
|
||||
ReaderOptions.ArchiveEncoding
|
||||
)
|
||||
),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
foreach (
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
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();
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Tar;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.IO;
|
||||
@@ -18,13 +19,16 @@ public partial class TarArchive
|
||||
{
|
||||
protected override async ValueTask SaveToAsync(
|
||||
Stream stream,
|
||||
WriterOptions options,
|
||||
IWriterOptions options,
|
||||
IAsyncEnumerable<TarArchiveEntry> oldEntries,
|
||||
IEnumerable<TarArchiveEntry> newEntries,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
using var writer = new TarWriter(stream, new TarWriterOptions(options));
|
||||
using var writer = new TarWriter(
|
||||
stream,
|
||||
options as TarWriterOptions ?? new TarWriterOptions(options)
|
||||
);
|
||||
await foreach (
|
||||
var entry in oldEntries.WithCancellation(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
@@ -123,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;
|
||||
@@ -147,7 +152,8 @@ public partial class TarArchive
|
||||
yield return new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(header, stream),
|
||||
CompressionType.None
|
||||
CompressionType.None,
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Tar;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.IO;
|
||||
@@ -58,7 +59,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;
|
||||
@@ -80,7 +82,8 @@ public partial class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVo
|
||||
yield return new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(header, stream),
|
||||
CompressionType.None
|
||||
CompressionType.None,
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -115,12 +118,15 @@ public partial class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVo
|
||||
|
||||
protected override void SaveTo(
|
||||
Stream stream,
|
||||
WriterOptions options,
|
||||
IWriterOptions options,
|
||||
IEnumerable<TarArchiveEntry> oldEntries,
|
||||
IEnumerable<TarArchiveEntry> newEntries
|
||||
)
|
||||
{
|
||||
using var writer = new TarWriter(stream, new TarWriterOptions(options));
|
||||
using var writer = new TarWriter(
|
||||
stream,
|
||||
options as TarWriterOptions ?? new TarWriterOptions(options)
|
||||
);
|
||||
foreach (var entry in oldEntries.Concat(newEntries))
|
||||
{
|
||||
if (entry.IsDirectory)
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Zip;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.IO;
|
||||
@@ -54,7 +55,8 @@ public partial class ZipArchive
|
||||
|
||||
yield return new ZipArchiveEntry(
|
||||
this,
|
||||
new SeekableZipFilePart(headerFactory.NotNull(), deh, s)
|
||||
new SeekableZipFilePart(headerFactory.NotNull(), deh, s),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
break;
|
||||
@@ -71,13 +73,16 @@ public partial class ZipArchive
|
||||
|
||||
protected override async ValueTask SaveToAsync(
|
||||
Stream stream,
|
||||
WriterOptions options,
|
||||
IWriterOptions options,
|
||||
IAsyncEnumerable<ZipArchiveEntry> oldEntries,
|
||||
IEnumerable<ZipArchiveEntry> newEntries,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
using var writer = new ZipWriter(stream, new ZipWriterOptions(options));
|
||||
using var writer = new ZipWriter(
|
||||
stream,
|
||||
options as ZipWriterOptions ?? new ZipWriterOptions(options)
|
||||
);
|
||||
await foreach (
|
||||
var entry in oldEntries.WithCancellation(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Zip;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
@@ -94,7 +95,8 @@ public partial class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVo
|
||||
|
||||
yield return new ZipArchiveEntry(
|
||||
this,
|
||||
new SeekableZipFilePart(headerFactory.NotNull(), deh, s)
|
||||
new SeekableZipFilePart(headerFactory.NotNull(), deh, s),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
break;
|
||||
@@ -113,12 +115,15 @@ public partial class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVo
|
||||
|
||||
protected override void SaveTo(
|
||||
Stream stream,
|
||||
WriterOptions options,
|
||||
IWriterOptions options,
|
||||
IEnumerable<ZipArchiveEntry> oldEntries,
|
||||
IEnumerable<ZipArchiveEntry> newEntries
|
||||
)
|
||||
{
|
||||
using var writer = new ZipWriter(stream, new ZipWriterOptions(options));
|
||||
using var writer = new ZipWriter(
|
||||
stream,
|
||||
options as ZipWriterOptions ?? new ZipWriterOptions(options)
|
||||
);
|
||||
foreach (var entry in oldEntries.Concat(newEntries))
|
||||
{
|
||||
if (entry.IsDirectory)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,34 +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?.WriteSymbolicLink is null)
|
||||
if (entry.Options.SymbolicLinkHandler is not null)
|
||||
{
|
||||
throw new ExtractionException(
|
||||
"Entry is a symbolic link but ExtractionOptions.WriteSymbolicLink delegate is null"
|
||||
);
|
||||
entry.Options.SymbolicLinkHandler(destinationFileName, entry.LinkTarget);
|
||||
}
|
||||
options.WriteSymbolicLink(destinationFileName, entry.LinkTarget);
|
||||
else
|
||||
{
|
||||
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,32 +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?.WriteSymbolicLink is null)
|
||||
if (entry.Options.SymbolicLinkHandler is not null)
|
||||
{
|
||||
throw new ExtractionException(
|
||||
"Entry is a symbolic link but ExtractionOptions.WriteSymbolicLink delegate is null"
|
||||
);
|
||||
entry.Options.SymbolicLinkHandler(destinationFileName, entry.LinkTarget);
|
||||
}
|
||||
options.WriteSymbolicLink(destinationFileName, entry.LinkTarget);
|
||||
else
|
||||
{
|
||||
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,40 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace SharpCompress.Common;
|
||||
|
||||
public class ExtractionOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// overwrite target if it exists
|
||||
/// </summary>
|
||||
public bool Overwrite { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// extract with internal directory structure
|
||||
/// </summary>
|
||||
public bool ExtractFullPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// preserve file time
|
||||
/// </summary>
|
||||
public bool PreserveFileTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// preserve windows file attributes
|
||||
/// </summary>
|
||||
public bool PreserveAttributes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Delegate for writing symbolic links to disk.
|
||||
/// sourcePath is where the symlink is created.
|
||||
/// targetPath is what the symlink refers to.
|
||||
/// </summary>
|
||||
public delegate void SymbolicLinkWriterDelegate(string sourcePath, string targetPath);
|
||||
|
||||
public SymbolicLinkWriterDelegate WriteSymbolicLink = (sourcePath, targetPath) =>
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"Could not write symlink {sourcePath} -> {targetPath}, for more information please see https://github.com/dotnet/runtime/issues/24271"
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common.GZip;
|
||||
|
||||
@@ -7,9 +8,12 @@ public partial class GZipEntry
|
||||
{
|
||||
internal static async IAsyncEnumerable<GZipEntry> GetEntriesAsync(
|
||||
Stream stream,
|
||||
OptionsBase options
|
||||
ReaderOptions options
|
||||
)
|
||||
{
|
||||
yield return new GZipEntry(await GZipFilePart.CreateAsync(stream, options.ArchiveEncoding));
|
||||
yield return new GZipEntry(
|
||||
await GZipFilePart.CreateAsync(stream, options.ArchiveEncoding),
|
||||
options
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common.GZip;
|
||||
|
||||
@@ -8,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;
|
||||
|
||||
@@ -38,9 +44,9 @@ public partial class GZipEntry : Entry
|
||||
|
||||
internal override IEnumerable<FilePart> Parts => _filePart.Empty();
|
||||
|
||||
internal static IEnumerable<GZipEntry> GetEntries(Stream stream, OptionsBase options)
|
||||
internal static IEnumerable<GZipEntry> GetEntries(Stream stream, ReaderOptions options)
|
||||
{
|
||||
yield return new GZipEntry(GZipFilePart.Create(stream, options.ArchiveEncoding));
|
||||
yield return new GZipEntry(GZipFilePart.Create(stream, options.ArchiveEncoding), options);
|
||||
}
|
||||
|
||||
// Async methods moved to GZipEntry.Async.cs
|
||||
|
||||
@@ -9,7 +9,7 @@ public class GZipVolume : Volume
|
||||
: base(stream, options, index) { }
|
||||
|
||||
public GZipVolume(FileInfo fileInfo, ReaderOptions options)
|
||||
: base(fileInfo.OpenRead(), options) => options.LeaveStreamOpen = false;
|
||||
: base(fileInfo.OpenRead(), options with { LeaveStreamOpen = false }) { }
|
||||
|
||||
public override bool IsFirstVolume => true;
|
||||
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
18
src/SharpCompress/Common/IsExternalInit.cs
Normal file
18
src/SharpCompress/Common/IsExternalInit.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
// This file is required for init-only properties to work on older target frameworks (.NET Framework 4.8, .NET Standard 2.0)
|
||||
// The IsExternalInit type is used by the compiler for records and init-only properties
|
||||
|
||||
#if NETFRAMEWORK || NETSTANDARD2_0
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace System.Runtime.CompilerServices;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved to be used by the compiler for tracking metadata.
|
||||
/// This class should not be used by developers in source code.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
internal static class IsExternalInit { }
|
||||
#endif
|
||||
6
src/SharpCompress/Common/Options/IEncodingOptions.cs
Normal file
6
src/SharpCompress/Common/Options/IEncodingOptions.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace SharpCompress.Common.Options;
|
||||
|
||||
public interface IEncodingOptions
|
||||
{
|
||||
IArchiveEncoding ArchiveEncoding { get; init; }
|
||||
}
|
||||
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; }
|
||||
}
|
||||
8
src/SharpCompress/Common/Options/IProgressOptions.cs
Normal file
8
src/SharpCompress/Common/Options/IProgressOptions.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace SharpCompress.Common.Options;
|
||||
|
||||
public interface IProgressOptions
|
||||
{
|
||||
IProgress<ProgressReport>? Progress { get; init; }
|
||||
}
|
||||
15
src/SharpCompress/Common/Options/IReaderOptions.cs
Normal file
15
src/SharpCompress/Common/Options/IReaderOptions.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace SharpCompress.Common.Options;
|
||||
|
||||
public interface IReaderOptions
|
||||
: IStreamOptions,
|
||||
IEncodingOptions,
|
||||
IProgressOptions,
|
||||
IExtractionOptions
|
||||
{
|
||||
bool LookForHeader { get; init; }
|
||||
string? Password { get; init; }
|
||||
bool DisableCheckIncomplete { get; init; }
|
||||
int BufferSize { get; init; }
|
||||
string? ExtensionHint { get; init; }
|
||||
int? RewindableBufferSize { get; init; }
|
||||
}
|
||||
6
src/SharpCompress/Common/Options/IStreamOptions.cs
Normal file
6
src/SharpCompress/Common/Options/IStreamOptions.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace SharpCompress.Common.Options;
|
||||
|
||||
public interface IStreamOptions
|
||||
{
|
||||
bool LeaveStreamOpen { get; init; }
|
||||
}
|
||||
9
src/SharpCompress/Common/Options/IWriterOptions.cs
Normal file
9
src/SharpCompress/Common/Options/IWriterOptions.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Common.Options;
|
||||
|
||||
public interface IWriterOptions : IStreamOptions, IEncodingOptions, IProgressOptions
|
||||
{
|
||||
CompressionType CompressionType { get; init; }
|
||||
int CompressionLevel { get; init; }
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace SharpCompress.Common;
|
||||
|
||||
public class OptionsBase
|
||||
{
|
||||
/// <summary>
|
||||
/// SharpCompress will keep the supplied streams open. Default is true.
|
||||
/// </summary>
|
||||
public bool LeaveStreamOpen { get; set; } = true;
|
||||
|
||||
public IArchiveEncoding ArchiveEncoding { get; set; } = new ArchiveEncoding();
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
@@ -7,6 +8,7 @@ using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.GZip;
|
||||
using SharpCompress.Archives.Tar;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.GZip;
|
||||
@@ -156,27 +158,33 @@ public class GZipFactory
|
||||
#region IWriterFactory
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IWriter OpenWriter(Stream stream, WriterOptions writerOptions)
|
||||
public IWriter OpenWriter(Stream stream, IWriterOptions writerOptions)
|
||||
{
|
||||
if (writerOptions.CompressionType != CompressionType.GZip)
|
||||
{
|
||||
throw new InvalidFormatException("GZip archives only support GZip compression type.");
|
||||
}
|
||||
return new GZipWriter(stream, new GZipWriterOptions(writerOptions));
|
||||
|
||||
GZipWriterOptions gzipOptions = writerOptions switch
|
||||
{
|
||||
GZipWriterOptions gwo => gwo,
|
||||
WriterOptions wo => new GZipWriterOptions(wo),
|
||||
_ => throw new ArgumentException(
|
||||
$"Expected WriterOptions or GZipWriterOptions, got {writerOptions.GetType().Name}",
|
||||
nameof(writerOptions)
|
||||
),
|
||||
};
|
||||
return new GZipWriter(stream, gzipOptions);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IAsyncWriter OpenAsyncWriter(
|
||||
Stream stream,
|
||||
WriterOptions writerOptions,
|
||||
IWriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (writerOptions.CompressionType != CompressionType.GZip)
|
||||
{
|
||||
throw new InvalidFormatException("GZip archives only support GZip compression type.");
|
||||
}
|
||||
return (IAsyncWriter)OpenWriter(stream, writerOptions);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.Tar;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Tar;
|
||||
@@ -216,13 +217,24 @@ public class TarFactory
|
||||
#region IWriterFactory
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IWriter OpenWriter(Stream stream, WriterOptions writerOptions) =>
|
||||
new TarWriter(stream, new TarWriterOptions(writerOptions));
|
||||
public IWriter OpenWriter(Stream stream, IWriterOptions writerOptions)
|
||||
{
|
||||
TarWriterOptions tarOptions = writerOptions switch
|
||||
{
|
||||
TarWriterOptions two => two,
|
||||
WriterOptions wo => new TarWriterOptions(wo),
|
||||
_ => throw new ArgumentException(
|
||||
$"Expected WriterOptions or TarWriterOptions, got {writerOptions.GetType().Name}",
|
||||
nameof(writerOptions)
|
||||
),
|
||||
};
|
||||
return new TarWriter(stream, tarOptions);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IAsyncWriter OpenAsyncWriter(
|
||||
Stream stream,
|
||||
WriterOptions writerOptions,
|
||||
IWriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
@@ -5,6 +6,7 @@ using System.Threading.Tasks;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.Zip;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Zip;
|
||||
@@ -185,13 +187,24 @@ public class ZipFactory
|
||||
#region IWriterFactory
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IWriter OpenWriter(Stream stream, WriterOptions writerOptions) =>
|
||||
new ZipWriter(stream, new ZipWriterOptions(writerOptions));
|
||||
public IWriter OpenWriter(Stream stream, IWriterOptions writerOptions)
|
||||
{
|
||||
ZipWriterOptions zipOptions = writerOptions switch
|
||||
{
|
||||
ZipWriterOptions zwo => zwo,
|
||||
WriterOptions wo => new ZipWriterOptions(wo),
|
||||
_ => throw new ArgumentException(
|
||||
$"Expected WriterOptions or ZipWriterOptions, got {writerOptions.GetType().Name}",
|
||||
nameof(writerOptions)
|
||||
),
|
||||
};
|
||||
return new ZipWriter(stream, zipOptions);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IAsyncWriter OpenAsyncWriter(
|
||||
Stream stream,
|
||||
WriterOptions writerOptions,
|
||||
IWriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
|
||||
@@ -74,7 +74,7 @@ public abstract partial class AceReader : AbstractReader<AceEntry, AceVolume>
|
||||
break;
|
||||
}
|
||||
|
||||
yield return new AceEntry(new AceFilePart((AceFileHeader)localHeader, stream));
|
||||
yield return new AceEntry(new AceFilePart((AceFileHeader)localHeader, stream), Options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ public abstract partial class AceReader : AbstractReader<AceEntry, AceVolume>
|
||||
break;
|
||||
}
|
||||
|
||||
yield return new AceEntry(new AceFilePart((AceFileHeader)localHeader, stream));
|
||||
yield return new AceEntry(new AceFilePart((AceFileHeader)localHeader, stream), Options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ public partial class ArcReader
|
||||
(header = await headerReader.ReadHeaderAsync(stream, CancellationToken.None)) != null
|
||||
)
|
||||
{
|
||||
yield return new ArcEntry(new ArcFilePart(header, stream));
|
||||
yield return new ArcEntry(new ArcFilePart(header, stream), Options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public partial class ArcReader : AbstractReader<ArcEntry, ArcVolume>
|
||||
ArcEntryHeader? header;
|
||||
while ((header = headerReader.ReadHeader(stream)) != null)
|
||||
{
|
||||
yield return new ArcEntry(new ArcFilePart(header, stream));
|
||||
yield return new ArcEntry(new ArcFilePart(header, stream), Options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,10 @@ public abstract partial class ArjReader : AbstractReader<ArjEntry, ArjVolume>
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new ArjEntry(new ArjFilePart((ArjLocalHeader)localHeader, stream));
|
||||
yield return new ArjEntry(
|
||||
new ArjFilePart((ArjLocalHeader)localHeader, stream),
|
||||
Options
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +138,10 @@ public abstract partial class ArjReader : AbstractReader<ArjEntry, ArjVolume>
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new ArjEntry(new ArjFilePart((ArjLocalHeader)localHeader, stream));
|
||||
yield return new ArjEntry(
|
||||
new ArjFilePart((ArjLocalHeader)localHeader, stream),
|
||||
Options
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,15 +14,14 @@ public static class IAsyncReaderExtensions
|
||||
/// </summary>
|
||||
public async ValueTask WriteEntryToDirectoryAsync(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
await ExtractionMethods
|
||||
.WriteEntryToDirectoryAsync(
|
||||
reader.Entry,
|
||||
destinationDirectory,
|
||||
options,
|
||||
reader.WriteEntryToFileAsync,
|
||||
async (path, ct) =>
|
||||
await reader.WriteEntryToFileAsync(path, ct).ConfigureAwait(false),
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
@@ -32,14 +31,12 @@ public static class IAsyncReaderExtensions
|
||||
/// </summary>
|
||||
public async ValueTask WriteEntryToFileAsync(
|
||||
string destinationFileName,
|
||||
ExtractionOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
await ExtractionMethods
|
||||
.WriteEntryToFileAsync(
|
||||
reader.Entry,
|
||||
destinationFileName,
|
||||
options,
|
||||
async (x, fm, ct) =>
|
||||
{
|
||||
using var fs = File.Open(destinationFileName, fm);
|
||||
@@ -54,28 +51,25 @@ public static class IAsyncReaderExtensions
|
||||
/// </summary>
|
||||
public async ValueTask WriteAllToDirectoryAsync(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
while (await reader.MoveToNextEntryAsync(cancellationToken))
|
||||
{
|
||||
await reader
|
||||
.WriteEntryToDirectoryAsync(destinationDirectory, options, cancellationToken)
|
||||
.WriteEntryToDirectoryAsync(destinationDirectory, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask WriteEntryToAsync(
|
||||
string destinationFileName,
|
||||
ExtractionOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
await ExtractionMethods
|
||||
.WriteEntryToFileAsync(
|
||||
reader.Entry,
|
||||
destinationFileName,
|
||||
options,
|
||||
async (x, fm, ct) =>
|
||||
{
|
||||
using var fs = File.Open(destinationFileName, fm);
|
||||
@@ -87,11 +81,10 @@ public static class IAsyncReaderExtensions
|
||||
|
||||
public async ValueTask WriteEntryToAsync(
|
||||
FileInfo destinationFileInfo,
|
||||
ExtractionOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
await reader
|
||||
.WriteEntryToAsync(destinationFileInfo.FullName, options, cancellationToken)
|
||||
.WriteEntryToAsync(destinationFileInfo.FullName, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Readers;
|
||||
@@ -22,42 +22,31 @@ public static class IReaderExtensions
|
||||
/// <summary>
|
||||
/// Extract all remaining unread entries to specific directory, retaining filename
|
||||
/// </summary>
|
||||
public void WriteAllToDirectory(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null
|
||||
)
|
||||
public void WriteAllToDirectory(string destinationDirectory)
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
reader.WriteEntryToDirectory(destinationDirectory, options);
|
||||
reader.WriteEntryToDirectory(destinationDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
public void WriteEntryToDirectory(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null
|
||||
) =>
|
||||
public void WriteEntryToDirectory(string destinationDirectory) =>
|
||||
ExtractionMethods.WriteEntryToDirectory(
|
||||
reader.Entry,
|
||||
destinationDirectory,
|
||||
options,
|
||||
reader.WriteEntryToFile
|
||||
(path) => reader.WriteEntryToFile(path)
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific file
|
||||
/// </summary>
|
||||
public void WriteEntryToFile(
|
||||
string destinationFileName,
|
||||
ExtractionOptions? options = null
|
||||
) =>
|
||||
public void WriteEntryToFile(string destinationFileName) =>
|
||||
ExtractionMethods.WriteEntryToFile(
|
||||
reader.Entry,
|
||||
destinationFileName,
|
||||
options,
|
||||
(x, fm) =>
|
||||
{
|
||||
using var fs = File.Open(destinationFileName, fm);
|
||||
|
||||
@@ -93,7 +93,7 @@ public abstract partial class RarReader : AbstractReader<RarReaderEntry, RarVolu
|
||||
foreach (var fp in volume.ReadFileParts())
|
||||
{
|
||||
ValidateArchive(volume);
|
||||
yield return new RarReaderEntry(volume.IsSolidArchive, fp);
|
||||
yield return new RarReaderEntry(volume.IsSolidArchive, fp, Options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ public abstract partial class RarReader : AbstractReader<RarReaderEntry, RarVolu
|
||||
await foreach (var fp in volume.ReadFilePartsAsync())
|
||||
{
|
||||
ValidateArchive(volume);
|
||||
yield return new RarReaderEntry(volume.IsSolidArchive, fp);
|
||||
yield return new RarReaderEntry(volume.IsSolidArchive, fp, Options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
|
||||
@@ -7,7 +8,8 @@ namespace SharpCompress.Readers.Rar;
|
||||
|
||||
public class RarReaderEntry : RarEntry
|
||||
{
|
||||
internal RarReaderEntry(bool solid, RarFilePart part)
|
||||
internal RarReaderEntry(bool solid, RarFilePart part, IReaderOptions readerOptions)
|
||||
: base(readerOptions)
|
||||
{
|
||||
Part = part;
|
||||
IsSolid = solid;
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
using System;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
namespace SharpCompress.Readers;
|
||||
|
||||
public class ReaderOptions : OptionsBase
|
||||
/// <summary>
|
||||
/// Options for configuring reader behavior when opening archives.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is immutable. Use the <c>with</c> expression to create modified copies:
|
||||
/// <code>
|
||||
/// var options = new ReaderOptions { Password = "secret" };
|
||||
/// options = options with { LeaveStreamOpen = false };
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
public sealed record ReaderOptions : IReaderOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The default buffer size for stream operations.
|
||||
@@ -15,27 +26,46 @@ public class ReaderOptions : OptionsBase
|
||||
)]
|
||||
public const int DefaultBufferSize = 0x10000;
|
||||
|
||||
/// <summary>
|
||||
/// SharpCompress will keep the supplied streams open. Default is true.
|
||||
/// </summary>
|
||||
public bool LeaveStreamOpen { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Encoding to use for archive entry names.
|
||||
/// </summary>
|
||||
public IArchiveEncoding ArchiveEncoding { get; init; } = new ArchiveEncoding();
|
||||
|
||||
/// <summary>
|
||||
/// Look for RarArchive (Check for self-extracting archives or cases where RarArchive isn't at the start of the file)
|
||||
/// </summary>
|
||||
public bool LookForHeader { get; set; }
|
||||
public bool LookForHeader { get; init; }
|
||||
|
||||
public string? Password { get; set; }
|
||||
/// <summary>
|
||||
/// Password for encrypted archives.
|
||||
/// </summary>
|
||||
public string? Password { get; init; }
|
||||
|
||||
public bool DisableCheckIncomplete { get; set; }
|
||||
/// <summary>
|
||||
/// Disable checking for incomplete archives.
|
||||
/// </summary>
|
||||
public bool DisableCheckIncomplete { get; init; }
|
||||
|
||||
public int BufferSize { get; set; } = Constants.BufferSize;
|
||||
/// <summary>
|
||||
/// Buffer size for stream operations.
|
||||
/// </summary>
|
||||
public int BufferSize { get; init; } = Constants.BufferSize;
|
||||
|
||||
/// <summary>
|
||||
/// Provide a hint for the extension of the archive being read, can speed up finding the correct decoder. Should be without the leading period in the form like: tar.gz or zip
|
||||
/// </summary>
|
||||
public string? ExtensionHint { get; set; }
|
||||
public string? ExtensionHint { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// An optional progress reporter for tracking extraction operations.
|
||||
/// When set, progress updates will be reported as entries are extracted.
|
||||
/// </summary>
|
||||
public IProgress<ProgressReport>? Progress { get; set; }
|
||||
public IProgress<ProgressReport>? Progress { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the rewindable buffer for non-seekable streams.
|
||||
@@ -78,5 +108,127 @@ public class ReaderOptions : OptionsBase
|
||||
/// using var reader = ReaderFactory.OpenReader(networkStream, options);
|
||||
/// </code>
|
||||
/// </example>
|
||||
public int? RewindableBufferSize { get; set; }
|
||||
public int? RewindableBufferSize { get; init; }
|
||||
|
||||
/// <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 ReaderOptions instance with default values.
|
||||
/// </summary>
|
||||
public ReaderOptions() { }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a ReaderOptions instance configured for safe extraction (no overwrite).
|
||||
/// </summary>
|
||||
public static ReaderOptions SafeExtract => new() { Overwrite = false };
|
||||
|
||||
/// <summary>
|
||||
/// Gets a ReaderOptions instance configured for flat extraction (no directory structure).
|
||||
/// </summary>
|
||||
public static ReaderOptions 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"
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ReaderOptions instance with the specified password.
|
||||
/// </summary>
|
||||
/// <param name="password">The password for encrypted archives.</param>
|
||||
public ReaderOptions(string? password) => Password = password;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ReaderOptions instance with the specified password and header search option.
|
||||
/// </summary>
|
||||
/// <param name="password">The password for encrypted archives.</param>
|
||||
/// <param name="lookForHeader">Whether to search for the archive header.</param>
|
||||
public ReaderOptions(string? password, bool lookForHeader)
|
||||
{
|
||||
Password = password;
|
||||
LookForHeader = lookForHeader;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ReaderOptions instance with the specified encoding.
|
||||
/// </summary>
|
||||
/// <param name="encoding">The encoding for archive entry names.</param>
|
||||
public ReaderOptions(IArchiveEncoding encoding) => ArchiveEncoding = encoding;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ReaderOptions instance with the specified password and encoding.
|
||||
/// </summary>
|
||||
/// <param name="password">The password for encrypted archives.</param>
|
||||
/// <param name="encoding">The encoding for archive entry names.</param>
|
||||
public ReaderOptions(string? password, IArchiveEncoding encoding)
|
||||
{
|
||||
Password = password;
|
||||
ArchiveEncoding = encoding;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ReaderOptions instance with the specified stream open behavior.
|
||||
/// </summary>
|
||||
/// <param name="leaveStreamOpen">Whether to leave the stream open after reading.</param>
|
||||
public ReaderOptions(bool leaveStreamOpen)
|
||||
{
|
||||
LeaveStreamOpen = leaveStreamOpen;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ReaderOptions instance with the specified stream open behavior and password.
|
||||
/// </summary>
|
||||
/// <param name="leaveStreamOpen">Whether to leave the stream open after reading.</param>
|
||||
/// <param name="password">The password for encrypted archives.</param>
|
||||
public ReaderOptions(bool leaveStreamOpen, string? password)
|
||||
{
|
||||
LeaveStreamOpen = leaveStreamOpen;
|
||||
Password = password;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ReaderOptions instance with the specified buffer size.
|
||||
/// </summary>
|
||||
/// <param name="bufferSize">The buffer size for stream operations.</param>
|
||||
public ReaderOptions(int bufferSize)
|
||||
{
|
||||
BufferSize = bufferSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public partial class TarReader
|
||||
StreamingMode.Streaming,
|
||||
stream,
|
||||
compressionType,
|
||||
Options.ArchiveEncoding
|
||||
Options.ArchiveEncoding,
|
||||
Options
|
||||
);
|
||||
}
|
||||
|
||||
@@ -124,7 +124,8 @@ public partial class TarReader : AbstractReader<TarEntry, TarVolume>
|
||||
StreamingMode.Streaming,
|
||||
stream,
|
||||
compressionType,
|
||||
Options.ArchiveEncoding
|
||||
Options.ArchiveEncoding,
|
||||
Options
|
||||
);
|
||||
|
||||
// GetEntriesAsync moved to TarReader.Async.cs
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Zip;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
|
||||
@@ -18,16 +19,22 @@ public partial class ZipReader
|
||||
{
|
||||
private readonly StreamingZipHeaderFactory _headerFactory;
|
||||
private readonly Stream _stream;
|
||||
private readonly IReaderOptions _options;
|
||||
|
||||
public ZipEntryAsyncEnumerable(StreamingZipHeaderFactory headerFactory, Stream stream)
|
||||
public ZipEntryAsyncEnumerable(
|
||||
StreamingZipHeaderFactory headerFactory,
|
||||
Stream stream,
|
||||
IReaderOptions options
|
||||
)
|
||||
{
|
||||
_headerFactory = headerFactory;
|
||||
_stream = stream;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
public IAsyncEnumerator<ZipEntry> GetAsyncEnumerator(
|
||||
CancellationToken cancellationToken = default
|
||||
) => new ZipEntryAsyncEnumerator(_headerFactory, _stream, cancellationToken);
|
||||
) => new ZipEntryAsyncEnumerator(_headerFactory, _stream, _options, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -37,15 +44,18 @@ public partial class ZipReader
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
private readonly IAsyncEnumerator<ZipHeader> _headerEnumerator;
|
||||
private readonly IReaderOptions _options;
|
||||
private ZipEntry? _current;
|
||||
|
||||
public ZipEntryAsyncEnumerator(
|
||||
StreamingZipHeaderFactory headerFactory,
|
||||
Stream stream,
|
||||
IReaderOptions options,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
_stream = stream;
|
||||
_options = options;
|
||||
_headerEnumerator = headerFactory
|
||||
.ReadStreamHeaderAsync(stream)
|
||||
.GetAsyncEnumerator(cancellationToken);
|
||||
@@ -67,7 +77,8 @@ public partial class ZipReader
|
||||
{
|
||||
case ZipHeaderType.LocalEntry:
|
||||
_current = new ZipEntry(
|
||||
new StreamingZipFilePart((LocalEntryHeader)header, _stream)
|
||||
new StreamingZipFilePart((LocalEntryHeader)header, _stream),
|
||||
_options
|
||||
);
|
||||
return true;
|
||||
case ZipHeaderType.DirectoryEntry:
|
||||
|
||||
@@ -74,7 +74,8 @@ public partial class ZipReader : AbstractReader<ZipEntry, ZipVolume>
|
||||
case ZipHeaderType.LocalEntry:
|
||||
{
|
||||
yield return new ZipEntry(
|
||||
new StreamingZipFilePart((LocalEntryHeader)h, stream)
|
||||
new StreamingZipFilePart((LocalEntryHeader)h, stream),
|
||||
Options
|
||||
);
|
||||
}
|
||||
break;
|
||||
@@ -99,7 +100,7 @@ public partial class ZipReader : AbstractReader<ZipEntry, ZipVolume>
|
||||
/// Returns entries asynchronously for streams that only support async reads.
|
||||
/// </summary>
|
||||
protected override IAsyncEnumerable<ZipEntry> GetEntriesAsync(Stream stream) =>
|
||||
new ZipEntryAsyncEnumerable(_headerFactory, stream);
|
||||
new ZipEntryAsyncEnumerable(_headerFactory, stream, Options);
|
||||
|
||||
// Async nested classes moved to ZipReader.Async.cs
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Writers;
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
public abstract partial class AbstractWriter(ArchiveType type, WriterOptions writerOptions)
|
||||
public abstract partial class AbstractWriter(ArchiveType type, IWriterOptions writerOptions)
|
||||
: IWriter,
|
||||
IAsyncWriter
|
||||
{
|
||||
@@ -23,7 +24,7 @@ public abstract partial class AbstractWriter(ArchiveType type, WriterOptions wri
|
||||
|
||||
public ArchiveType WriterType { get; } = type;
|
||||
|
||||
protected WriterOptions WriterOptions { get; } = writerOptions;
|
||||
protected IWriterOptions WriterOptions { get; } = writerOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Wraps the source stream with a progress-reporting stream if progress reporting is enabled.
|
||||
|
||||
@@ -1,18 +1,100 @@
|
||||
using System;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using D = SharpCompress.Compressors.Deflate;
|
||||
|
||||
namespace SharpCompress.Writers.GZip;
|
||||
|
||||
public class GZipWriterOptions : WriterOptions
|
||||
/// <summary>
|
||||
/// Options for configuring GZip writer behavior.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is immutable. Use the <c>with</c> expression to create modified copies:
|
||||
/// <code>
|
||||
/// var options = new GZipWriterOptions { CompressionLevel = 9 };
|
||||
/// options = options with { LeaveStreamOpen = false };
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
public sealed record GZipWriterOptions : IWriterOptions
|
||||
{
|
||||
public GZipWriterOptions()
|
||||
: base(CompressionType.GZip, (int)(D.CompressionLevel.Default)) { }
|
||||
/// <summary>
|
||||
/// The compression type (always GZip for this writer).
|
||||
/// </summary>
|
||||
public CompressionType CompressionType { get; init; } = CompressionType.GZip;
|
||||
|
||||
internal GZipWriterOptions(WriterOptions options)
|
||||
: base(options.CompressionType, (int)(D.CompressionLevel.Default))
|
||||
/// <summary>
|
||||
/// The compression level to be used (0-9 for Deflate).
|
||||
/// </summary>
|
||||
public int CompressionLevel { get; init; } = (int)D.CompressionLevel.Default;
|
||||
|
||||
/// <summary>
|
||||
/// SharpCompress will keep the supplied streams open. Default is true.
|
||||
/// </summary>
|
||||
public bool LeaveStreamOpen { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Encoding to use for archive entry names.
|
||||
/// </summary>
|
||||
public IArchiveEncoding ArchiveEncoding { get; init; } = new ArchiveEncoding();
|
||||
|
||||
/// <summary>
|
||||
/// An optional progress reporter for tracking compression operations.
|
||||
/// </summary>
|
||||
public IProgress<ProgressReport>? Progress { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GZipWriterOptions instance with default values.
|
||||
/// </summary>
|
||||
public GZipWriterOptions() { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GZipWriterOptions instance with the specified compression level.
|
||||
/// </summary>
|
||||
/// <param name="compressionLevel">The compression level (0-9).</param>
|
||||
public GZipWriterOptions(int compressionLevel)
|
||||
{
|
||||
CompressionLevel = compressionLevel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GZipWriterOptions instance with the specified Deflate compression level.
|
||||
/// </summary>
|
||||
/// <param name="compressionLevel">The Deflate compression level.</param>
|
||||
public GZipWriterOptions(D.CompressionLevel compressionLevel)
|
||||
{
|
||||
CompressionLevel = (int)compressionLevel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GZipWriterOptions instance with the specified stream open behavior.
|
||||
/// </summary>
|
||||
/// <param name="leaveStreamOpen">Whether to leave the stream open after writing.</param>
|
||||
public GZipWriterOptions(bool leaveStreamOpen)
|
||||
{
|
||||
LeaveStreamOpen = leaveStreamOpen;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GZipWriterOptions instance from an existing WriterOptions instance.
|
||||
/// </summary>
|
||||
/// <param name="options">The WriterOptions to copy values from.</param>
|
||||
public GZipWriterOptions(WriterOptions options)
|
||||
{
|
||||
CompressionLevel = options.CompressionLevel;
|
||||
LeaveStreamOpen = options.LeaveStreamOpen;
|
||||
ArchiveEncoding = options.ArchiveEncoding;
|
||||
Progress = options.Progress;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GZipWriterOptions instance from an existing IWriterOptions instance.
|
||||
/// </summary>
|
||||
/// <param name="options">The IWriterOptions to copy values from.</param>
|
||||
public GZipWriterOptions(IWriterOptions options)
|
||||
{
|
||||
CompressionLevel = options.CompressionLevel;
|
||||
LeaveStreamOpen = options.LeaveStreamOpen;
|
||||
ArchiveEncoding = options.ArchiveEncoding;
|
||||
Progress = options.Progress;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Factories;
|
||||
|
||||
namespace SharpCompress.Writers;
|
||||
|
||||
public interface IWriterFactory : IFactory
|
||||
{
|
||||
IWriter OpenWriter(Stream stream, WriterOptions writerOptions);
|
||||
IWriter OpenWriter(Stream stream, IWriterOptions writerOptions);
|
||||
|
||||
IAsyncWriter OpenAsyncWriter(
|
||||
Stream stream,
|
||||
WriterOptions writerOptions,
|
||||
IWriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#if NET8_0_OR_GREATER
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
namespace SharpCompress.Writers;
|
||||
|
||||
public interface IWriterOpenable<TWriterOptions>
|
||||
where TWriterOptions : WriterOptions
|
||||
where TWriterOptions : IWriterOptions
|
||||
{
|
||||
public static abstract IWriter OpenWriter(string filePath, TWriterOptions writerOptions);
|
||||
|
||||
|
||||
@@ -1,33 +1,120 @@
|
||||
using System;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
|
||||
namespace SharpCompress.Writers.Tar;
|
||||
|
||||
public class TarWriterOptions : WriterOptions
|
||||
/// <summary>
|
||||
/// Options for configuring Tar writer behavior.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is immutable. Use the <c>with</c> expression to create modified copies:
|
||||
/// <code>
|
||||
/// var options = new TarWriterOptions(CompressionType.GZip, true);
|
||||
/// options = options with { HeaderFormat = TarHeaderWriteFormat.V7 };
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
public sealed record TarWriterOptions : IWriterOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The compression type to use for the archive.
|
||||
/// </summary>
|
||||
public CompressionType CompressionType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The compression level to be used when the compression type supports variable levels.
|
||||
/// </summary>
|
||||
public int CompressionLevel { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// SharpCompress will keep the supplied streams open. Default is true.
|
||||
/// </summary>
|
||||
public bool LeaveStreamOpen { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Encoding to use for archive entry names.
|
||||
/// </summary>
|
||||
public IArchiveEncoding ArchiveEncoding { get; init; } = new ArchiveEncoding();
|
||||
|
||||
/// <summary>
|
||||
/// An optional progress reporter for tracking compression operations.
|
||||
/// </summary>
|
||||
public IProgress<ProgressReport>? Progress { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if archive should be finalized (by 2 empty blocks) on close.
|
||||
/// </summary>
|
||||
public bool FinalizeArchiveOnClose { get; }
|
||||
public bool FinalizeArchiveOnClose { get; init; } = true;
|
||||
|
||||
public TarHeaderWriteFormat HeaderFormat { get; }
|
||||
/// <summary>
|
||||
/// The format to use when writing tar headers.
|
||||
/// </summary>
|
||||
public TarHeaderWriteFormat HeaderFormat { get; init; } =
|
||||
TarHeaderWriteFormat.GNU_TAR_LONG_LINK;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new TarWriterOptions instance with the specified compression type and finalization option.
|
||||
/// </summary>
|
||||
/// <param name="compressionType">The compression type for the archive.</param>
|
||||
/// <param name="finalizeArchiveOnClose">Whether to finalize the archive on close.</param>
|
||||
public TarWriterOptions(CompressionType compressionType, bool finalizeArchiveOnClose)
|
||||
{
|
||||
CompressionType = compressionType;
|
||||
FinalizeArchiveOnClose = finalizeArchiveOnClose;
|
||||
CompressionLevel = compressionType switch
|
||||
{
|
||||
CompressionType.ZStandard => 3,
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new TarWriterOptions instance with the specified compression type, finalization option, and header format.
|
||||
/// </summary>
|
||||
/// <param name="compressionType">The compression type for the archive.</param>
|
||||
/// <param name="finalizeArchiveOnClose">Whether to finalize the archive on close.</param>
|
||||
/// <param name="headerFormat">The tar header format.</param>
|
||||
public TarWriterOptions(
|
||||
CompressionType compressionType,
|
||||
bool finalizeArchiveOnClose,
|
||||
TarHeaderWriteFormat headerFormat = TarHeaderWriteFormat.GNU_TAR_LONG_LINK
|
||||
TarHeaderWriteFormat headerFormat
|
||||
)
|
||||
: base(compressionType)
|
||||
: this(compressionType, finalizeArchiveOnClose)
|
||||
{
|
||||
FinalizeArchiveOnClose = finalizeArchiveOnClose;
|
||||
HeaderFormat = headerFormat;
|
||||
}
|
||||
|
||||
internal TarWriterOptions(WriterOptions options)
|
||||
: this(options.CompressionType, true)
|
||||
/// <summary>
|
||||
/// Creates a new TarWriterOptions instance from an existing WriterOptions instance.
|
||||
/// </summary>
|
||||
/// <param name="options">The WriterOptions to copy values from.</param>
|
||||
public TarWriterOptions(WriterOptions options)
|
||||
{
|
||||
LeaveStreamOpen = options.LeaveStreamOpen;
|
||||
CompressionType = options.CompressionType;
|
||||
CompressionLevel = options.CompressionLevel;
|
||||
LeaveStreamOpen = options.LeaveStreamOpen;
|
||||
ArchiveEncoding = options.ArchiveEncoding;
|
||||
Progress = options.Progress;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new TarWriterOptions instance from an existing IWriterOptions instance.
|
||||
/// </summary>
|
||||
/// <param name="options">The IWriterOptions to copy values from.</param>
|
||||
public TarWriterOptions(IWriterOptions options)
|
||||
{
|
||||
CompressionType = options.CompressionType;
|
||||
CompressionLevel = options.CompressionLevel;
|
||||
LeaveStreamOpen = options.LeaveStreamOpen;
|
||||
ArchiveEncoding = options.ArchiveEncoding;
|
||||
Progress = options.Progress;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicit conversion from CompressionType to TarWriterOptions with finalize enabled.
|
||||
/// </summary>
|
||||
/// <param name="compressionType">The compression type.</param>
|
||||
public static implicit operator TarWriterOptions(CompressionType compressionType) =>
|
||||
new(compressionType, true);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
namespace SharpCompress.Writers;
|
||||
|
||||
@@ -11,7 +12,7 @@ public static class WriterFactory
|
||||
public static IWriter OpenWriter(
|
||||
string filePath,
|
||||
ArchiveType archiveType,
|
||||
WriterOptions writerOptions
|
||||
IWriterOptions writerOptions
|
||||
)
|
||||
{
|
||||
filePath.NotNullOrEmpty(nameof(filePath));
|
||||
@@ -21,7 +22,7 @@ public static class WriterFactory
|
||||
public static IWriter OpenWriter(
|
||||
FileInfo fileInfo,
|
||||
ArchiveType archiveType,
|
||||
WriterOptions writerOptions
|
||||
IWriterOptions writerOptions
|
||||
)
|
||||
{
|
||||
fileInfo.NotNull(nameof(fileInfo));
|
||||
@@ -31,7 +32,7 @@ public static class WriterFactory
|
||||
public static IAsyncWriter OpenAsyncWriter(
|
||||
string filePath,
|
||||
ArchiveType archiveType,
|
||||
WriterOptions writerOptions,
|
||||
IWriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
@@ -47,7 +48,7 @@ public static class WriterFactory
|
||||
public static IAsyncWriter OpenAsyncWriter(
|
||||
FileInfo fileInfo,
|
||||
ArchiveType archiveType,
|
||||
WriterOptions writerOptions,
|
||||
IWriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
@@ -63,7 +64,7 @@ public static class WriterFactory
|
||||
public static IWriter OpenWriter(
|
||||
Stream stream,
|
||||
ArchiveType archiveType,
|
||||
WriterOptions writerOptions
|
||||
IWriterOptions writerOptions
|
||||
)
|
||||
{
|
||||
var factory = Factories
|
||||
@@ -89,7 +90,7 @@ public static class WriterFactory
|
||||
public static IAsyncWriter OpenAsyncWriter(
|
||||
Stream stream,
|
||||
ArchiveType archiveType,
|
||||
WriterOptions writerOptions,
|
||||
IWriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
|
||||
@@ -1,11 +1,58 @@
|
||||
using System;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using D = SharpCompress.Compressors.Deflate;
|
||||
|
||||
namespace SharpCompress.Writers;
|
||||
|
||||
public class WriterOptions : OptionsBase
|
||||
/// <summary>
|
||||
/// Options for configuring writer behavior when creating archives.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is immutable. Use the <c>with</c> expression to create modified copies:
|
||||
/// <code>
|
||||
/// var options = new WriterOptions(CompressionType.Zip);
|
||||
/// options = options with { LeaveStreamOpen = false };
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
public sealed record WriterOptions : IWriterOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The compression type to use for the archive.
|
||||
/// </summary>
|
||||
public CompressionType CompressionType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The compression level to be used when the compression type supports variable levels.
|
||||
/// Valid ranges depend on the compression algorithm:
|
||||
/// - Deflate/GZip: 0-9 (0=no compression, 6=default, 9=best compression)
|
||||
/// - ZStandard: 1-22 (1=fastest, 3=default, 22=best compression)
|
||||
/// Note: BZip2 and LZMA do not support compression levels in this implementation.
|
||||
/// Defaults are set automatically based on compression type in the constructor.
|
||||
/// </summary>
|
||||
public int CompressionLevel { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// SharpCompress will keep the supplied streams open. Default is true.
|
||||
/// </summary>
|
||||
public bool LeaveStreamOpen { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Encoding to use for archive entry names.
|
||||
/// </summary>
|
||||
public IArchiveEncoding ArchiveEncoding { get; init; } = new ArchiveEncoding();
|
||||
|
||||
/// <summary>
|
||||
/// An optional progress reporter for tracking compression operations.
|
||||
/// When set, progress updates will be reported as entries are written.
|
||||
/// </summary>
|
||||
public IProgress<ProgressReport>? Progress { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new WriterOptions instance with the specified compression type.
|
||||
/// Compression level is automatically set based on the compression type.
|
||||
/// </summary>
|
||||
/// <param name="compressionType">The compression type for the archive.</param>
|
||||
public WriterOptions(CompressionType compressionType)
|
||||
{
|
||||
CompressionType = compressionType;
|
||||
@@ -19,30 +66,48 @@ public class WriterOptions : OptionsBase
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new WriterOptions instance with the specified compression type and level.
|
||||
/// </summary>
|
||||
/// <param name="compressionType">The compression type for the archive.</param>
|
||||
/// <param name="compressionLevel">The compression level (algorithm-specific).</param>
|
||||
public WriterOptions(CompressionType compressionType, int compressionLevel)
|
||||
{
|
||||
CompressionType = compressionType;
|
||||
CompressionLevel = compressionLevel;
|
||||
}
|
||||
|
||||
public CompressionType CompressionType { get; set; }
|
||||
/// <summary>
|
||||
/// Creates a new WriterOptions instance with the specified compression type and stream open behavior.
|
||||
/// </summary>
|
||||
/// <param name="compressionType">The compression type for the archive.</param>
|
||||
/// <param name="leaveStreamOpen">Whether to leave the stream open after writing.</param>
|
||||
public WriterOptions(CompressionType compressionType, bool leaveStreamOpen)
|
||||
: this(compressionType)
|
||||
{
|
||||
LeaveStreamOpen = leaveStreamOpen;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The compression level to be used when the compression type supports variable levels.
|
||||
/// Valid ranges depend on the compression algorithm:
|
||||
/// - Deflate/GZip: 0-9 (0=no compression, 6=default, 9=best compression)
|
||||
/// - ZStandard: 1-22 (1=fastest, 3=default, 22=best compression)
|
||||
/// Note: BZip2 and LZMA do not support compression levels in this implementation.
|
||||
/// Defaults are set automatically based on compression type in the constructor.
|
||||
/// Creates a new WriterOptions instance with the specified compression type, level, and stream open behavior.
|
||||
/// </summary>
|
||||
public int CompressionLevel { get; set; }
|
||||
/// <param name="compressionType">The compression type for the archive.</param>
|
||||
/// <param name="compressionLevel">The compression level (algorithm-specific).</param>
|
||||
/// <param name="leaveStreamOpen">Whether to leave the stream open after writing.</param>
|
||||
public WriterOptions(
|
||||
CompressionType compressionType,
|
||||
int compressionLevel,
|
||||
bool leaveStreamOpen
|
||||
)
|
||||
: this(compressionType, compressionLevel)
|
||||
{
|
||||
LeaveStreamOpen = leaveStreamOpen;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An optional progress reporter for tracking compression operations.
|
||||
/// When set, progress updates will be reported as entries are written.
|
||||
/// Implicit conversion from CompressionType to WriterOptions.
|
||||
/// </summary>
|
||||
public IProgress<ProgressReport>? Progress { get; set; }
|
||||
|
||||
/// <param name="compressionType">The compression type.</param>
|
||||
public static implicit operator WriterOptions(CompressionType compressionType) =>
|
||||
new(compressionType);
|
||||
}
|
||||
|
||||
@@ -1,78 +1,52 @@
|
||||
using System;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using D = SharpCompress.Compressors.Deflate;
|
||||
|
||||
namespace SharpCompress.Writers.Zip;
|
||||
|
||||
public class ZipWriterOptions : WriterOptions
|
||||
/// <summary>
|
||||
/// Options for configuring Zip writer behavior.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is immutable. Use the <c>with</c> expression to create modified copies:
|
||||
/// <code>
|
||||
/// var options = new ZipWriterOptions(CompressionType.Zip);
|
||||
/// options = options with { UseZip64 = true };
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
public sealed record ZipWriterOptions : IWriterOptions
|
||||
{
|
||||
public ZipWriterOptions(
|
||||
CompressionType compressionType,
|
||||
CompressionLevel compressionLevel = D.CompressionLevel.Default
|
||||
)
|
||||
: base(compressionType, (int)compressionLevel) { }
|
||||
|
||||
internal ZipWriterOptions(WriterOptions options)
|
||||
: base(options.CompressionType)
|
||||
{
|
||||
LeaveStreamOpen = options.LeaveStreamOpen;
|
||||
ArchiveEncoding = options.ArchiveEncoding;
|
||||
CompressionLevel = options.CompressionLevel;
|
||||
|
||||
if (options is ZipWriterOptions writerOptions)
|
||||
{
|
||||
UseZip64 = writerOptions.UseZip64;
|
||||
ArchiveComment = writerOptions.ArchiveComment;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The compression type to use for the archive.
|
||||
/// </summary>
|
||||
public CompressionType CompressionType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the compression level for Deflate compression (0-9).
|
||||
/// This is a convenience method that sets the CompressionLevel property for Deflate compression.
|
||||
/// The compression level to be used when the compression type supports variable levels.
|
||||
/// </summary>
|
||||
/// <param name="level">Deflate compression level (0=no compression, 6=default, 9=best compression)</param>
|
||||
public void SetDeflateCompressionLevel(CompressionLevel level)
|
||||
{
|
||||
CompressionLevel = (int)level;
|
||||
}
|
||||
public int CompressionLevel { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the compression level for ZStandard compression (1-22).
|
||||
/// This is a convenience method that sets the CompressionLevel property for ZStandard compression.
|
||||
/// SharpCompress will keep the supplied streams open. Default is true.
|
||||
/// </summary>
|
||||
/// <param name="level">ZStandard compression level (1=fastest, 3=default, 22=best compression)</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when level is not between 1 and 22</exception>
|
||||
public void SetZStandardCompressionLevel(int level)
|
||||
{
|
||||
if (level < 1 || level > 22)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(level),
|
||||
"ZStandard compression level must be between 1 and 22"
|
||||
);
|
||||
}
|
||||
|
||||
CompressionLevel = level;
|
||||
}
|
||||
public bool LeaveStreamOpen { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Legacy property for Deflate compression levels.
|
||||
/// Valid range: 0-9 (0=no compression, 6=default, 9=best compression).
|
||||
/// Encoding to use for archive entry names.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property is deprecated. Use <see cref="WriterOptions.CompressionLevel"/> or <see cref="SetDeflateCompressionLevel"/> instead.
|
||||
/// </remarks>
|
||||
[Obsolete(
|
||||
"Use CompressionLevel property or SetDeflateCompressionLevel method instead. This property will be removed in a future version."
|
||||
)]
|
||||
public CompressionLevel DeflateCompressionLevel
|
||||
{
|
||||
get => (CompressionLevel)Math.Min(CompressionLevel, 9);
|
||||
set => CompressionLevel = (int)value;
|
||||
}
|
||||
public IArchiveEncoding ArchiveEncoding { get; init; } = new ArchiveEncoding();
|
||||
|
||||
public string? ArchiveComment { get; set; }
|
||||
/// <summary>
|
||||
/// An optional progress reporter for tracking compression operations.
|
||||
/// </summary>
|
||||
public IProgress<ProgressReport>? Progress { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional comment for the archive.
|
||||
/// </summary>
|
||||
public string? ArchiveComment { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value indicating if zip64 support is enabled.
|
||||
@@ -81,5 +55,72 @@ public class ZipWriterOptions : WriterOptions
|
||||
/// Archives larger than 4GiB are supported as long as all streams
|
||||
/// are less than 4GiB in length.
|
||||
/// </summary>
|
||||
public bool UseZip64 { get; set; }
|
||||
public bool UseZip64 { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ZipWriterOptions instance with the specified compression type.
|
||||
/// </summary>
|
||||
/// <param name="compressionType">The compression type for the archive.</param>
|
||||
public ZipWriterOptions(CompressionType compressionType)
|
||||
{
|
||||
CompressionType = compressionType;
|
||||
CompressionLevel = compressionType switch
|
||||
{
|
||||
CompressionType.ZStandard => 3,
|
||||
CompressionType.Deflate => (int)D.CompressionLevel.Default,
|
||||
CompressionType.Deflate64 => (int)D.CompressionLevel.Default,
|
||||
CompressionType.GZip => (int)D.CompressionLevel.Default,
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ZipWriterOptions instance with the specified compression type and level.
|
||||
/// </summary>
|
||||
/// <param name="compressionType">The compression type for the archive.</param>
|
||||
/// <param name="compressionLevel">The compression level (algorithm-specific).</param>
|
||||
public ZipWriterOptions(CompressionType compressionType, int compressionLevel)
|
||||
{
|
||||
CompressionType = compressionType;
|
||||
CompressionLevel = compressionLevel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ZipWriterOptions instance with the specified compression type and Deflate compression level.
|
||||
/// </summary>
|
||||
/// <param name="compressionType">The compression type for the archive.</param>
|
||||
/// <param name="compressionLevel">The Deflate compression level.</param>
|
||||
public ZipWriterOptions(CompressionType compressionType, D.CompressionLevel compressionLevel)
|
||||
: this(compressionType, (int)compressionLevel) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ZipWriterOptions instance from an existing WriterOptions instance.
|
||||
/// </summary>
|
||||
/// <param name="options">The WriterOptions to copy values from.</param>
|
||||
public ZipWriterOptions(WriterOptions options)
|
||||
: this(options.CompressionType, options.CompressionLevel)
|
||||
{
|
||||
LeaveStreamOpen = options.LeaveStreamOpen;
|
||||
ArchiveEncoding = options.ArchiveEncoding;
|
||||
Progress = options.Progress;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ZipWriterOptions instance from an existing IWriterOptions instance.
|
||||
/// </summary>
|
||||
/// <param name="options">The IWriterOptions to copy values from.</param>
|
||||
public ZipWriterOptions(IWriterOptions options)
|
||||
: this(options.CompressionType, options.CompressionLevel)
|
||||
{
|
||||
LeaveStreamOpen = options.LeaveStreamOpen;
|
||||
ArchiveEncoding = options.ArchiveEncoding;
|
||||
Progress = options.Progress;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicit conversion from CompressionType to ZipWriterOptions.
|
||||
/// </summary>
|
||||
/// <param name="compressionType">The compression type.</param>
|
||||
public static implicit operator ZipWriterOptions(CompressionType compressionType) =>
|
||||
new(compressionType);
|
||||
}
|
||||
|
||||
@@ -216,9 +216,9 @@
|
||||
"net10.0": {
|
||||
"Microsoft.NET.ILLink.Tasks": {
|
||||
"type": "Direct",
|
||||
"requested": "[10.0.2, )",
|
||||
"resolved": "10.0.2",
|
||||
"contentHash": "sXdDtMf2qcnbygw9OdE535c2lxSxrZP8gO4UhDJ0xiJbl1wIqXS1OTcTDFTIJPOFd6Mhcm8gPEthqWGUxBsTqw=="
|
||||
"requested": "[10.0.0, )",
|
||||
"resolved": "10.0.0",
|
||||
"contentHash": "kICGrGYEzCNI3wPzfEXcwNHgTvlvVn9yJDhSdRK+oZQy4jvYH529u7O0xf5ocQKzOMjfS07+3z9PKRIjrFMJDA=="
|
||||
},
|
||||
"Microsoft.NETFramework.ReferenceAssemblies": {
|
||||
"type": "Direct",
|
||||
@@ -264,9 +264,9 @@
|
||||
"net8.0": {
|
||||
"Microsoft.NET.ILLink.Tasks": {
|
||||
"type": "Direct",
|
||||
"requested": "[8.0.23, )",
|
||||
"resolved": "8.0.23",
|
||||
"contentHash": "GqHiB1HbbODWPbY/lc5xLQH8siEEhNA0ptpJCC6X6adtAYNEzu5ZlqV3YHA3Gh7fuEwgA8XqVwMtH2KNtuQM1Q=="
|
||||
"requested": "[8.0.22, )",
|
||||
"resolved": "8.0.22",
|
||||
"contentHash": "MhcMithKEiyyNkD2ZfbDZPmcOdi0GheGfg8saEIIEfD/fol3iHmcV8TsZkD4ZYz5gdUuoX4YtlVySUU7Sxl9SQ=="
|
||||
},
|
||||
"Microsoft.NETFramework.ReferenceAssemblies": {
|
||||
"type": "Direct",
|
||||
|
||||
@@ -80,10 +80,7 @@ public class AceReaderAsyncTests : ReaderTests
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
Assert.Equal(expectedCompression, reader.Entry.CompressionType);
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -105,10 +102,7 @@ public class AceReaderAsyncTests : ReaderTests
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
Assert.Equal(expectedCompression, reader.Entry.CompressionType);
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
CompareFilesByPath(
|
||||
@@ -130,10 +124,7 @@ public class AceReaderAsyncTests : ReaderTests
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,10 +62,7 @@ public class ArchiveTests : ReaderTests
|
||||
}
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
stream.ThrowOnDispose = false;
|
||||
}
|
||||
@@ -151,10 +148,7 @@ public class ArchiveTests : ReaderTests
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
@@ -192,10 +186,7 @@ public class ArchiveTests : ReaderTests
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -224,10 +215,7 @@ public class ArchiveTests : ReaderTests
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -299,10 +287,7 @@ public class ArchiveTests : ReaderTests
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -346,16 +331,7 @@ public class ArchiveTests : ReaderTests
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true,
|
||||
PreserveAttributes = true,
|
||||
PreserveFileTime = true,
|
||||
}
|
||||
);
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFilesEx();
|
||||
@@ -401,11 +377,9 @@ public class ArchiveTests : ReaderTests
|
||||
int? compressionLevel = null
|
||||
)
|
||||
{
|
||||
var writerOptions = new ZipWriterOptions(compressionType);
|
||||
if (compressionLevel.HasValue)
|
||||
{
|
||||
writerOptions.CompressionLevel = compressionLevel.Value;
|
||||
}
|
||||
var writerOptions = compressionLevel.HasValue
|
||||
? new WriterOptions(compressionType, compressionLevel.Value)
|
||||
: new WriterOptions(compressionType);
|
||||
return WriterFactory.OpenWriter(stream, ArchiveType.Zip, writerOptions);
|
||||
}
|
||||
|
||||
@@ -415,12 +389,9 @@ public class ArchiveTests : ReaderTests
|
||||
int? compressionLevel = null
|
||||
)
|
||||
{
|
||||
var writerOptions = new ZipWriterOptions(compressionType);
|
||||
if (compressionLevel.HasValue)
|
||||
{
|
||||
writerOptions.CompressionLevel = compressionLevel.Value;
|
||||
writerOptions.LeaveStreamOpen = true;
|
||||
}
|
||||
var writerOptions = compressionLevel.HasValue
|
||||
? new WriterOptions(compressionType, compressionLevel.Value, leaveStreamOpen: true)
|
||||
: new WriterOptions(compressionType) { LeaveStreamOpen = true };
|
||||
return WriterFactory.OpenAsyncWriter(
|
||||
new AsyncOnlyStream(stream),
|
||||
ArchiveType.Zip,
|
||||
@@ -655,10 +626,7 @@ public class ArchiveTests : ReaderTests
|
||||
var entry in archive.EntriesAsync.Where(entry => !entry.IsDirectory)
|
||||
)
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await entry.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
|
||||
@@ -104,10 +104,7 @@ public class ArjReaderAsyncTests : ReaderTests
|
||||
{
|
||||
Assert.Equal(expectedCompression.Value, reader.Entry.CompressionType);
|
||||
}
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -129,10 +126,7 @@ public class ArjReaderAsyncTests : ReaderTests
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
Assert.Equal(expectedCompression, reader.Entry.CompressionType);
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
CompareFilesByPath(
|
||||
@@ -155,10 +149,7 @@ public class ArjReaderAsyncTests : ReaderTests
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,9 @@ public class ExtractAllTests : TestBase
|
||||
public async ValueTask ExtractAllEntriesAsync(string archivePath)
|
||||
{
|
||||
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, archivePath);
|
||||
var options = new ExtractionOptions() { ExtractFullPath = true, Overwrite = true };
|
||||
|
||||
await using var archive = await ArchiveFactory.OpenAsyncArchive(testArchive);
|
||||
await archive.WriteToDirectoryAsync(SCRATCH_FILES_PATH, options);
|
||||
await archive.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -38,9 +37,8 @@ public class ExtractAllTests : TestBase
|
||||
public void ExtractAllEntriesSync(string archivePath)
|
||||
{
|
||||
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, archivePath);
|
||||
var options = new ExtractionOptions() { ExtractFullPath = true, Overwrite = true };
|
||||
|
||||
using var archive = ArchiveFactory.OpenArchive(testArchive);
|
||||
archive.WriteToDirectory(SCRATCH_FILES_PATH, options);
|
||||
archive.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,10 +43,7 @@ public class ExtractAllEntriesTests : TestBase
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
reader.WriteEntryToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||||
|
||||
completed += reader.Entry.Size;
|
||||
var progress = completed / totalSize;
|
||||
|
||||
@@ -27,7 +27,11 @@ public class ExtractionTests : TestBase
|
||||
using (var stream = File.Create(testArchive))
|
||||
{
|
||||
using var writer = (ZipWriter)
|
||||
WriterFactory.OpenWriter(stream, ArchiveType.Zip, CompressionType.Deflate);
|
||||
WriterFactory.OpenWriter(
|
||||
stream,
|
||||
ArchiveType.Zip,
|
||||
new WriterOptions(CompressionType.Deflate)
|
||||
);
|
||||
|
||||
// Create a test file to add to the archive
|
||||
var testFilePath = Path.Combine(SCRATCH2_FILES_PATH, "testfile.txt");
|
||||
@@ -43,12 +47,7 @@ public class ExtractionTests : TestBase
|
||||
|
||||
// This should not throw an exception even if Path.GetFullPath returns
|
||||
// a path with different casing than the actual directory
|
||||
var exception = Record.Exception(() =>
|
||||
reader.WriteAllToDirectory(
|
||||
extractPath,
|
||||
new ExtractionOptions { ExtractFullPath = false, Overwrite = true }
|
||||
)
|
||||
);
|
||||
var exception = Record.Exception(() => reader.WriteAllToDirectory(extractPath));
|
||||
|
||||
Assert.Null(exception);
|
||||
}
|
||||
@@ -72,7 +71,11 @@ public class ExtractionTests : TestBase
|
||||
using (var stream = File.Create(testArchive))
|
||||
{
|
||||
using var writer = (ZipWriter)
|
||||
WriterFactory.OpenWriter(stream, ArchiveType.Zip, CompressionType.Deflate);
|
||||
WriterFactory.OpenWriter(
|
||||
stream,
|
||||
ArchiveType.Zip,
|
||||
new WriterOptions(CompressionType.Deflate)
|
||||
);
|
||||
|
||||
var testFilePath = Path.Combine(SCRATCH2_FILES_PATH, "testfile2.txt");
|
||||
File.WriteAllText(testFilePath, "Test content");
|
||||
@@ -87,10 +90,7 @@ public class ExtractionTests : TestBase
|
||||
using var reader = ReaderFactory.OpenReader(stream);
|
||||
|
||||
var exception = Assert.Throws<ExtractionException>(() =>
|
||||
reader.WriteAllToDirectory(
|
||||
extractPath,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
)
|
||||
reader.WriteAllToDirectory(extractPath)
|
||||
);
|
||||
|
||||
Assert.Contains("outside of the destination", exception.Message);
|
||||
|
||||
@@ -29,10 +29,7 @@ public class AsyncTests : TestBase
|
||||
#endif
|
||||
await using var reader = await ReaderFactory.OpenAsyncReader(new AsyncOnlyStream(stream));
|
||||
|
||||
await reader.WriteAllToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteAllToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
|
||||
// Just verify some files were extracted
|
||||
var extractedFiles = Directory.GetFiles(
|
||||
@@ -147,11 +144,7 @@ public class AsyncTests : TestBase
|
||||
cancellationToken: cts.Token
|
||||
);
|
||||
|
||||
await reader.WriteAllToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true },
|
||||
cts.Token
|
||||
);
|
||||
await reader.WriteAllToDirectoryAsync(SCRATCH_FILES_PATH, cts.Token);
|
||||
|
||||
// Just verify some files were extracted
|
||||
var extractedFiles = Directory.GetFiles(
|
||||
|
||||
@@ -27,7 +27,7 @@ public class GZipWriterAsyncTests : WriterTests
|
||||
var writer = WriterFactory.OpenAsyncWriter(
|
||||
new AsyncOnlyStream(stream),
|
||||
ArchiveType.GZip,
|
||||
CompressionType.GZip
|
||||
new WriterOptions(CompressionType.GZip)
|
||||
)
|
||||
)
|
||||
{
|
||||
@@ -67,7 +67,7 @@ public class GZipWriterAsyncTests : WriterTests
|
||||
using var writer = WriterFactory.OpenWriter(
|
||||
new AsyncOnlyStream(stream),
|
||||
ArchiveType.GZip,
|
||||
CompressionType.BZip2
|
||||
new WriterOptions(CompressionType.BZip2)
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Writers;
|
||||
using SharpCompress.Writers.GZip;
|
||||
@@ -22,7 +22,11 @@ public class GZipWriterTests : WriterTests
|
||||
)
|
||||
)
|
||||
using (
|
||||
var writer = WriterFactory.OpenWriter(stream, ArchiveType.GZip, CompressionType.GZip)
|
||||
var writer = WriterFactory.OpenWriter(
|
||||
stream,
|
||||
ArchiveType.GZip,
|
||||
new WriterOptions(CompressionType.GZip)
|
||||
)
|
||||
)
|
||||
{
|
||||
writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
|
||||
@@ -61,7 +65,7 @@ public class GZipWriterTests : WriterTests
|
||||
using var writer = WriterFactory.OpenWriter(
|
||||
stream,
|
||||
ArchiveType.GZip,
|
||||
CompressionType.BZip2
|
||||
new WriterOptions(CompressionType.BZip2)
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -80,10 +80,7 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
if (!entry.IsDirectory)
|
||||
{
|
||||
Assert.Equal(CompressionType.Rar, entry.CompressionType);
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await entry.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,10 +104,7 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await entry.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -141,10 +135,7 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
using var archive = ArchiveFactory.OpenArchive(stream);
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await entry.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,10 +149,7 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await entry.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -183,10 +171,7 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
Assert.False(archive.IsSolid);
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await entry.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -273,10 +258,7 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
Assert.Equal(archive.IsSolid, isSolid);
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await entry.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,10 +319,7 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await entry.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -639,10 +618,7 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
using var archive = ArchiveFactory.OpenArchive(stream);
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await entry.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
@@ -665,10 +641,7 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
Assert.Equal(compression, reader.Entry.CompressionType);
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -676,10 +649,7 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
|
||||
await foreach (var entry in archive.EntriesAsync.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await entry.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
@@ -690,10 +660,7 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
using var archive = ArchiveFactory.OpenArchive(testArchive);
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await entry.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
@@ -710,14 +677,52 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
);
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await entry.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests for Issue #1050 - RAR extraction with WriteToDirectoryAsync creates folders
|
||||
/// but places all files at the top level instead of in their subdirectories.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async ValueTask Rar_Issue1050_WriteToDirectoryAsync_ExtractsToSubdirectories()
|
||||
{
|
||||
var testFile = "Rar.issue1050.rar";
|
||||
using var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testFile));
|
||||
await using var archive = RarArchive.OpenAsyncArchive(fileStream);
|
||||
|
||||
// Extract using archive.WriteToDirectoryAsync without explicit options
|
||||
await archive.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
|
||||
// Verify files are in their subdirectories, not at the root
|
||||
Assert.True(
|
||||
File.Exists(Path.Combine(SCRATCH_FILES_PATH, "PhysicsBraid", "263825.tr11dtp")),
|
||||
"File should be in PhysicsBraid subdirectory"
|
||||
);
|
||||
Assert.True(
|
||||
File.Exists(Path.Combine(SCRATCH_FILES_PATH, "Animations", "15441.tr11anim")),
|
||||
"File should be in Animations subdirectory"
|
||||
);
|
||||
Assert.True(
|
||||
File.Exists(Path.Combine(SCRATCH_FILES_PATH, "Braid", "766728.tr11dtp")),
|
||||
"File should be in Braid subdirectory"
|
||||
);
|
||||
Assert.True(
|
||||
File.Exists(Path.Combine(SCRATCH_FILES_PATH, "Braid", "766832.tr11dtp")),
|
||||
"File should be in Braid subdirectory"
|
||||
);
|
||||
Assert.True(
|
||||
File.Exists(Path.Combine(SCRATCH_FILES_PATH, "HeadBraid", "321353.tr11modeldata")),
|
||||
"File should be in HeadBraid subdirectory"
|
||||
);
|
||||
|
||||
// NOTE: The file size check is omitted because there's a separate pre-existing bug
|
||||
// in the async RAR stream implementation that causes incorrect file sizes.
|
||||
// This test only verifies the directory structure fix.
|
||||
}
|
||||
|
||||
private async ValueTask ArchiveOpenStreamReadAsync(
|
||||
ReaderOptions? readerOptions,
|
||||
params string[] testArchives
|
||||
@@ -730,10 +735,7 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
);
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await entry.WriteToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
@@ -79,10 +79,7 @@ public class RarArchiveTests : ArchiveTests
|
||||
if (!entry.IsDirectory)
|
||||
{
|
||||
Assert.Equal(CompressionType.Rar, entry.CompressionType);
|
||||
entry.WriteToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,10 +103,7 @@ public class RarArchiveTests : ArchiveTests
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -137,10 +131,7 @@ public class RarArchiveTests : ArchiveTests
|
||||
using var archive = ArchiveFactory.OpenArchive(stream);
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,10 +145,7 @@ public class RarArchiveTests : ArchiveTests
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -177,10 +165,7 @@ public class RarArchiveTests : ArchiveTests
|
||||
Assert.False(archive.IsSolid);
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -266,10 +251,7 @@ public class RarArchiveTests : ArchiveTests
|
||||
Assert.Equal(archive.IsSolid, isSolid);
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,10 +309,7 @@ public class RarArchiveTests : ArchiveTests
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -722,6 +701,47 @@ public class RarArchiveTests : ArchiveTests
|
||||
Assert.Contains("unpacked file size does not match header", exception.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests for Issue #1050 - RAR extraction with WriteToDirectory creates folders
|
||||
/// but places all files at the top level instead of in their subdirectories.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Rar_Issue1050_WriteToDirectory_ExtractsToSubdirectories()
|
||||
{
|
||||
var testFile = "Rar.issue1050.rar";
|
||||
using var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testFile));
|
||||
using var archive = RarArchive.OpenArchive(fileStream);
|
||||
|
||||
// Extract using archive.WriteToDirectory without explicit options
|
||||
archive.WriteToDirectory(SCRATCH_FILES_PATH);
|
||||
|
||||
// Verify files are in their subdirectories, not at the root
|
||||
Assert.True(
|
||||
File.Exists(Path.Combine(SCRATCH_FILES_PATH, "PhysicsBraid", "263825.tr11dtp")),
|
||||
"File should be in PhysicsBraid subdirectory"
|
||||
);
|
||||
Assert.True(
|
||||
File.Exists(Path.Combine(SCRATCH_FILES_PATH, "Animations", "15441.tr11anim")),
|
||||
"File should be in Animations subdirectory"
|
||||
);
|
||||
Assert.True(
|
||||
File.Exists(Path.Combine(SCRATCH_FILES_PATH, "Braid", "766728.tr11dtp")),
|
||||
"File should be in Braid subdirectory"
|
||||
);
|
||||
Assert.True(
|
||||
File.Exists(Path.Combine(SCRATCH_FILES_PATH, "Braid", "766832.tr11dtp")),
|
||||
"File should be in Braid subdirectory"
|
||||
);
|
||||
Assert.True(
|
||||
File.Exists(Path.Combine(SCRATCH_FILES_PATH, "HeadBraid", "321353.tr11modeldata")),
|
||||
"File should be in HeadBraid subdirectory"
|
||||
);
|
||||
|
||||
// Verify the exact file size of 766832.tr11dtp matches the archive entry size
|
||||
var fileInfo = new FileInfo(Path.Combine(SCRATCH_FILES_PATH, "Braid", "766832.tr11dtp"));
|
||||
Assert.Equal(4867620, fileInfo.Length); // Expected: 4,867,620 bytes
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test case for malformed RAR archives that previously caused infinite loops.
|
||||
/// This test verifies that attempting to read entries from a potentially malformed
|
||||
|
||||
@@ -49,10 +49,7 @@ public class RarReaderAsyncTests : ReaderTests
|
||||
IAsyncReader reader = (IAsyncReader)baseReader;
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -83,10 +80,7 @@ public class RarReaderAsyncTests : ReaderTests
|
||||
IAsyncReader reader = (IAsyncReader)baseReader;
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -132,10 +126,7 @@ public class RarReaderAsyncTests : ReaderTests
|
||||
IAsyncReader reader = (IAsyncReader)baseReader;
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
foreach (var stream in streams)
|
||||
@@ -262,10 +253,7 @@ public class RarReaderAsyncTests : ReaderTests
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType);
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
CompareFilesByPath(
|
||||
@@ -289,10 +277,7 @@ public class RarReaderAsyncTests : ReaderTests
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType);
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -334,10 +319,7 @@ public class RarReaderAsyncTests : ReaderTests
|
||||
if (reader.Entry.Key.NotNull().Contains("jpg"))
|
||||
{
|
||||
Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType);
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,10 +342,7 @@ public class RarReaderAsyncTests : ReaderTests
|
||||
if (reader.Entry.Key.NotNull().Contains("jpg"))
|
||||
{
|
||||
Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType);
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -385,10 +364,7 @@ public class RarReaderAsyncTests : ReaderTests
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
Assert.Equal(expectedCompression, reader.Entry.CompressionType);
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
|
||||
@@ -46,10 +46,7 @@ public class RarReaderTests : ReaderTests
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
reader.WriteEntryToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -80,10 +77,7 @@ public class RarReaderTests : ReaderTests
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
reader.WriteEntryToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -128,10 +122,7 @@ public class RarReaderTests : ReaderTests
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
reader.WriteEntryToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
foreach (var stream in streams)
|
||||
@@ -236,10 +227,7 @@ public class RarReaderTests : ReaderTests
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType);
|
||||
reader.WriteEntryToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
CompareFilesByPath(
|
||||
@@ -259,10 +247,7 @@ public class RarReaderTests : ReaderTests
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType);
|
||||
reader.WriteEntryToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
@@ -298,10 +283,7 @@ public class RarReaderTests : ReaderTests
|
||||
if (reader.Entry.Key.NotNull().Contains("jpg"))
|
||||
{
|
||||
Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType);
|
||||
reader.WriteEntryToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -324,10 +306,7 @@ public class RarReaderTests : ReaderTests
|
||||
if (reader.Entry.Key.NotNull().Contains("jpg"))
|
||||
{
|
||||
Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType);
|
||||
reader.WriteEntryToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,11 +41,11 @@ public abstract class ReaderTests : TestBase
|
||||
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
|
||||
options ??= new ReaderOptions { BufferSize = 0x20000 };
|
||||
|
||||
options.LeaveStreamOpen = true;
|
||||
readImpl(testArchive, options);
|
||||
var optionsWithStreamOpen = options with { LeaveStreamOpen = true };
|
||||
readImpl(testArchive, optionsWithStreamOpen);
|
||||
|
||||
options.LeaveStreamOpen = false;
|
||||
readImpl(testArchive, options);
|
||||
var optionsWithStreamClosed = options with { LeaveStreamOpen = false };
|
||||
readImpl(testArchive, optionsWithStreamClosed);
|
||||
|
||||
VerifyFiles();
|
||||
}
|
||||
@@ -89,10 +89,7 @@ public abstract class ReaderTests : TestBase
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
Assert.Equal(expectedCompression, reader.Entry.CompressionType);
|
||||
reader.WriteEntryToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,10 +100,7 @@ public abstract class ReaderTests : TestBase
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
reader.WriteEntryToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,11 +135,21 @@ public abstract class ReaderTests : TestBase
|
||||
|
||||
options ??= new ReaderOptions() { BufferSize = 0x20000 };
|
||||
|
||||
options.LeaveStreamOpen = true;
|
||||
await ReadImplAsync(testArchive, expectedCompression, options, cancellationToken);
|
||||
var optionsWithStreamOpen = options with { LeaveStreamOpen = true };
|
||||
await ReadImplAsync(
|
||||
testArchive,
|
||||
expectedCompression,
|
||||
optionsWithStreamOpen,
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
options.LeaveStreamOpen = false;
|
||||
await ReadImplAsync(testArchive, expectedCompression, options, cancellationToken);
|
||||
var optionsWithStreamClosed = options with { LeaveStreamOpen = false };
|
||||
await ReadImplAsync(
|
||||
testArchive,
|
||||
expectedCompression,
|
||||
optionsWithStreamClosed,
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
VerifyFiles();
|
||||
}
|
||||
@@ -203,11 +207,7 @@ public abstract class ReaderTests : TestBase
|
||||
Assert.Equal(expectedCompression, reader.Entry.CompressionType);
|
||||
}
|
||||
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true },
|
||||
cancellationToken
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,10 +224,7 @@ public abstract class ReaderTests : TestBase
|
||||
{
|
||||
Assert.Equal(compressionType, reader.Entry.CompressionType);
|
||||
|
||||
reader.WriteEntryToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
|
||||
CompareFilesByPath(
|
||||
@@ -271,10 +268,7 @@ public abstract class ReaderTests : TestBase
|
||||
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
reader.WriteEntryToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
|
||||
VerifyFiles();
|
||||
|
||||
@@ -268,10 +268,7 @@ public class SevenZipArchiveTests : ArchiveTests
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
reader.WriteEntryToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -148,8 +148,10 @@ public class TarArchiveAsyncTests : ArchiveTests
|
||||
await using (var archive = TarArchive.CreateAsyncArchive())
|
||||
{
|
||||
await archive.AddAllFromDirectoryAsync(ORIGINAL_FILES_PATH);
|
||||
var twopt = new TarWriterOptions(CompressionType.None, true);
|
||||
twopt.ArchiveEncoding = new ArchiveEncoding { Default = Encoding.GetEncoding(866) };
|
||||
var twopt = new TarWriterOptions(CompressionType.None, true)
|
||||
{
|
||||
ArchiveEncoding = new ArchiveEncoding { Default = Encoding.GetEncoding(866) },
|
||||
};
|
||||
await archive.SaveToAsync(scratchPath, twopt);
|
||||
}
|
||||
CompareArchivesByPath(unmodified, scratchPath);
|
||||
@@ -196,8 +198,7 @@ public class TarArchiveAsyncTests : ArchiveTests
|
||||
{
|
||||
using var mstm = new MemoryStream();
|
||||
var enc = new ArchiveEncoding { Default = Encoding.UTF8 };
|
||||
var twopt = new TarWriterOptions(CompressionType.None, true);
|
||||
twopt.ArchiveEncoding = enc;
|
||||
var twopt = new TarWriterOptions(CompressionType.None, true) { ArchiveEncoding = enc };
|
||||
var fname = new string((char)0x3042, length);
|
||||
using (var tw = new TarWriter(mstm, twopt))
|
||||
using (var input = new MemoryStream(new byte[32]))
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using SharpCompress.Archives.Tar;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Writers;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Tar;
|
||||
@@ -80,7 +81,7 @@ public class TarArchiveDirectoryTests : TestBase
|
||||
|
||||
using (var fileStream = File.Create(scratchPath))
|
||||
{
|
||||
archive.SaveTo(fileStream, CompressionType.None);
|
||||
archive.SaveTo(fileStream, new WriterOptions(CompressionType.None));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,13 @@ public class TarArchiveTests : ArchiveTests
|
||||
|
||||
// Step 1: create a tar file containing a file with the test name
|
||||
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive)))
|
||||
using (var writer = WriterFactory.OpenWriter(stream, ArchiveType.Tar, CompressionType.None))
|
||||
using (
|
||||
var writer = WriterFactory.OpenWriter(
|
||||
stream,
|
||||
ArchiveType.Tar,
|
||||
new WriterOptions(CompressionType.None)
|
||||
)
|
||||
)
|
||||
using (Stream inputStream = new MemoryStream())
|
||||
{
|
||||
var sw = new StreamWriter(inputStream);
|
||||
@@ -94,7 +100,13 @@ public class TarArchiveTests : ArchiveTests
|
||||
|
||||
// Step 1: create a tar file containing a file with a long name
|
||||
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive)))
|
||||
using (var writer = WriterFactory.OpenWriter(stream, ArchiveType.Tar, CompressionType.None))
|
||||
using (
|
||||
var writer = WriterFactory.OpenWriter(
|
||||
stream,
|
||||
ArchiveType.Tar,
|
||||
new WriterOptions(CompressionType.None)
|
||||
)
|
||||
)
|
||||
using (Stream inputStream = new MemoryStream())
|
||||
{
|
||||
var sw = new StreamWriter(inputStream);
|
||||
@@ -162,8 +174,10 @@ public class TarArchiveTests : ArchiveTests
|
||||
using (var archive = TarArchive.CreateArchive())
|
||||
{
|
||||
archive.AddAllFromDirectory(ORIGINAL_FILES_PATH);
|
||||
var twopt = new TarWriterOptions(CompressionType.None, true);
|
||||
twopt.ArchiveEncoding = new ArchiveEncoding { Default = Encoding.GetEncoding(866) };
|
||||
var twopt = new TarWriterOptions(CompressionType.None, true)
|
||||
{
|
||||
ArchiveEncoding = new ArchiveEncoding { Default = Encoding.GetEncoding(866) },
|
||||
};
|
||||
archive.SaveTo(scratchPath, twopt);
|
||||
}
|
||||
CompareArchivesByPath(unmodified, scratchPath);
|
||||
@@ -180,7 +194,7 @@ public class TarArchiveTests : ArchiveTests
|
||||
using (var archive = TarArchive.OpenArchive(unmodified))
|
||||
{
|
||||
archive.AddEntry("jpg\\test.jpg", jpg);
|
||||
archive.SaveTo(scratchPath, CompressionType.None);
|
||||
archive.SaveTo(scratchPath, new WriterOptions(CompressionType.None));
|
||||
}
|
||||
CompareArchivesByPath(modified, scratchPath);
|
||||
}
|
||||
@@ -198,7 +212,7 @@ public class TarArchiveTests : ArchiveTests
|
||||
x.Key.NotNull().EndsWith("jpg", StringComparison.OrdinalIgnoreCase)
|
||||
);
|
||||
archive.RemoveEntry(entry);
|
||||
archive.SaveTo(scratchPath, CompressionType.None);
|
||||
archive.SaveTo(scratchPath, new WriterOptions(CompressionType.None));
|
||||
}
|
||||
CompareArchivesByPath(modified, scratchPath);
|
||||
}
|
||||
@@ -228,8 +242,7 @@ public class TarArchiveTests : ArchiveTests
|
||||
{
|
||||
using var mstm = new MemoryStream();
|
||||
var enc = new ArchiveEncoding { Default = Encoding.UTF8 };
|
||||
var twopt = new TarWriterOptions(CompressionType.None, true);
|
||||
twopt.ArchiveEncoding = enc;
|
||||
var twopt = new TarWriterOptions(CompressionType.None, true) { ArchiveEncoding = enc };
|
||||
var fname = new string((char)0x3042, length);
|
||||
using (var tw = new TarWriter(mstm, twopt))
|
||||
using (var input = new MemoryStream(new byte[32]))
|
||||
|
||||
@@ -33,10 +33,7 @@ public class TarReaderAsyncTests : ReaderTests
|
||||
x++;
|
||||
if (x % 2 == 0)
|
||||
{
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,10 +31,7 @@ public class TarReaderTests : ReaderTests
|
||||
x++;
|
||||
if (x % 2 == 0)
|
||||
{
|
||||
reader.WriteEntryToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,10 +47,7 @@ public class WriterTests : TestBase
|
||||
SharpCompressStream.CreateNonDisposing(stream),
|
||||
readerOptions
|
||||
);
|
||||
reader.WriteAllToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true }
|
||||
);
|
||||
reader.WriteAllToDirectory(SCRATCH_FILES_PATH);
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
@@ -97,11 +94,7 @@ public class WriterTests : TestBase
|
||||
readerOptions,
|
||||
cancellationToken
|
||||
);
|
||||
await reader.WriteAllToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true },
|
||||
cancellationToken
|
||||
);
|
||||
await reader.WriteAllToDirectoryAsync(SCRATCH_FILES_PATH, cancellationToken);
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user