Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ profiler-snapshots/
.DS_Store
*.snupkg
benchmark-results/
/.opencode
11 changes: 4 additions & 7 deletions src/SharpCompress/Archives/ArchiveFactory.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ public static async ValueTask<IAsyncArchive> OpenAsyncArchive(
)
{
cancellationToken.ThrowIfCancellationRequested();
streams.NotNull(nameof(streams));
var streamsArray = streams;
var streamsArray = streams.RequireReadable();
streamsArray.RequireSeekable();
if (streamsArray.Count == 0)
{
throw new ArchiveOperationException("No streams");
Expand Down Expand Up @@ -143,11 +143,8 @@ internal static async ValueTask<T> FindFactoryAsync<T>(
)
where T : IFactory
{
stream.NotNull(nameof(stream));
if (!stream.CanRead || !stream.CanSeek)
{
throw new ArgumentException("Stream should be readable and seekable");
}
stream.RequireReadable();
stream.RequireSeekable();

var factories = Factory.Factories.OfType<T>();

Expand Down
27 changes: 8 additions & 19 deletions src/SharpCompress/Archives/ArchiveFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ public static IArchive OpenArchive(

public static IArchive OpenArchive(IReadOnlyList<Stream> streams, ReaderOptions? options = null)
{
streams.NotNull(nameof(streams));
var streamsArray = streams;
var streamsArray = streams.RequireReadable();
streamsArray.RequireSeekable();
if (streamsArray.Count == 0)
{
throw new ArchiveOperationException("No streams");
Expand Down Expand Up @@ -121,11 +121,8 @@ public static T FindFactory<T>(FileInfo finfo)
public static T FindFactory<T>(Stream stream)
where T : IFactory
{
stream.NotNull(nameof(stream));
if (!stream.CanRead || !stream.CanSeek)
{
throw new ArgumentException("Stream should be readable and seekable");
}
stream.RequireReadable();
stream.RequireSeekable();

var factories = Factory.Factories.OfType<T>();

Expand Down Expand Up @@ -160,12 +157,8 @@ public static bool IsArchive(string filePath, out ArchiveType? type)
public static bool IsArchive(Stream stream, out ArchiveType? type)
{
type = null;
stream.NotNull(nameof(stream));

if (!stream.CanRead || !stream.CanSeek)
{
throw new ArgumentException("Stream should be readable and seekable");
}
stream.RequireReadable();
stream.RequireSeekable();

var startPosition = stream.Position;

Expand Down Expand Up @@ -199,12 +192,8 @@ public static bool IsArchive(Stream stream, out ArchiveType? type)
CancellationToken cancellationToken = default
)
{
stream.NotNull(nameof(stream));

if (!stream.CanRead || !stream.CanSeek)
{
throw new ArgumentException("Stream should be readable and seekable");
}
stream.RequireReadable();
stream.RequireSeekable();

var startPosition = stream.Position;

Expand Down
12 changes: 4 additions & 8 deletions src/SharpCompress/Archives/GZip/GZipArchive.Factory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ public static IWritableArchive<GZipWriterOptions> OpenArchive(
ReaderOptions? readerOptions = null
)
{
streams.NotNull(nameof(streams));
var strms = streams;
var strms = streams.RequireReadable();
strms.RequireSeekable();
return new GZipArchive(
new SourceStream(
strms[0],

Copilot AI Apr 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenArchive(IReadOnlyList<Stream>) indexes strms[0] without guarding against an empty stream list, which will throw an IndexOutOfRangeException. Add an explicit Count == 0 check and throw a more meaningful exception (consistent with ArchiveFactory.OpenArchive's "No streams" behavior).

Copilot uses AI. Check for mistakes.
Expand All @@ -92,12 +92,8 @@ public static IWritableArchive<GZipWriterOptions> OpenArchive(
ReaderOptions? readerOptions = null
)
{
stream.NotNull(nameof(stream));

if (stream is not { CanSeek: true })
{
throw new ArgumentException("Stream must be seekable", nameof(stream));
}
stream.RequireReadable();
stream.RequireSeekable();

return new GZipArchive(
new SourceStream(stream, _ => null, readerOptions ?? ReaderOptions.ForExternalStream)
Expand Down
12 changes: 4 additions & 8 deletions src/SharpCompress/Archives/Rar/RarArchive.Factory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,8 @@ public static IRarArchive OpenArchive(FileInfo fileInfo, ReaderOptions? readerOp

public static IRarArchive OpenArchive(Stream stream, ReaderOptions? readerOptions = null)
{
stream.NotNull(nameof(stream));

if (stream is not { CanSeek: true })
{
throw new ArgumentException("Stream must be seekable", nameof(stream));
}
stream.RequireReadable();
stream.RequireSeekable();

return new RarArchive(
new SourceStream(stream, _ => null, readerOptions ?? ReaderOptions.ForExternalStream)
Expand Down Expand Up @@ -91,8 +87,8 @@ public static IRarArchive OpenArchive(
ReaderOptions? readerOptions = null
)
{
streams.NotNull(nameof(streams));
var strms = streams;
var strms = streams.RequireReadable();
strms.RequireSeekable();
return new RarArchive(
new SourceStream(
strms[0],

Copilot AI Apr 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenArchive(IReadOnlyList<Stream>) indexes strms[0] without guarding against an empty stream list, which will throw an IndexOutOfRangeException. Add an explicit Count == 0 check and throw a more meaningful exception (consistent with ArchiveFactory.OpenArchive's "No streams" behavior).

Copilot uses AI. Check for mistakes.
Expand Down
12 changes: 4 additions & 8 deletions src/SharpCompress/Archives/SevenZip/SevenZipArchive.Factory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ public static IArchive OpenArchive(
ReaderOptions? readerOptions = null
)
{
streams.NotNull(nameof(streams));
var strms = streams;
var strms = streams.RequireReadable();
strms.RequireSeekable();

Copilot AI Apr 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenArchive(IReadOnlyList<Stream>) indexes strms[0] without guarding against an empty stream list, which will throw an IndexOutOfRangeException. Add an explicit Count == 0 check and throw a more meaningful exception (consistent with ArchiveFactory.OpenArchive's "No streams" behavior).

Suggested change
strms.RequireSeekable();
strms.RequireSeekable();
if (strms.Count == 0)
{
throw new ArgumentException("No streams", nameof(streams));
}

Copilot uses AI. Check for mistakes.
return new SevenZipArchive(
new SourceStream(
strms[0],
Expand All @@ -84,12 +84,8 @@ public static IArchive OpenArchive(

public static IArchive OpenArchive(Stream stream, ReaderOptions? readerOptions = null)
{
stream.NotNull(nameof(stream));

if (stream is not { CanSeek: true })
{
throw new ArgumentException("Stream must be seekable", nameof(stream));
}
stream.RequireReadable();
stream.RequireSeekable();

return new SevenZipArchive(
new SourceStream(stream, _ => null, readerOptions ?? ReaderOptions.ForExternalStream)
Expand Down
19 changes: 8 additions & 11 deletions src/SharpCompress/Archives/Tar/TarArchive.Factory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ public static IWritableArchive<TarWriterOptions> OpenArchive(
ReaderOptions? readerOptions = null
)
{
streams.NotNull(nameof(streams));
var strms = streams;
var strms = streams.RequireReadable();
strms.RequireSeekable();
var sourceStream = new SourceStream(
strms[0],
i => i < strms.Count ? strms[i] : null,

Copilot AI Apr 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenArchive(IReadOnlyList<Stream>) indexes strms[0] without guarding against an empty stream list, which will throw an IndexOutOfRangeException. Add an explicit Count == 0 check and throw a more meaningful exception (consistent with ArchiveFactory.OpenArchive's "No streams" behavior).

Copilot uses AI. Check for mistakes.
Expand All @@ -86,12 +86,8 @@ public static IWritableArchive<TarWriterOptions> OpenArchive(
ReaderOptions? readerOptions = null
)
{
stream.NotNull(nameof(stream));

if (stream is not { CanSeek: true })
{
throw new ArgumentException("Stream must be seekable", nameof(stream));
}
stream.RequireReadable();
stream.RequireSeekable();

return OpenArchive([stream], readerOptions);
}
Expand All @@ -102,7 +98,8 @@ public static async ValueTask<IWritableAsyncArchive<TarWriterOptions>> OpenAsync
CancellationToken cancellationToken = default
)
{
stream.NotNull(nameof(stream));
stream.RequireReadable();
stream.RequireSeekable();
var sourceStream = new SourceStream(
stream,
Comment on lines 99 to 103

Copilot AI Apr 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenAsyncArchive(Stream, ..., CancellationToken) doesn't call cancellationToken.ThrowIfCancellationRequested() at the start, while other OpenAsyncArchive overloads in this type do. Add the early cancellation check for consistency and to fail fast before doing any work when the token is already canceled.

Copilot uses AI. Check for mistakes.
i => null,
Expand Down Expand Up @@ -158,8 +155,8 @@ public static async ValueTask<IWritableAsyncArchive<TarWriterOptions>> OpenAsync
)
{
cancellationToken.ThrowIfCancellationRequested();
streams.NotNull(nameof(streams));
var strms = streams;
var strms = streams.RequireReadable();
strms.RequireSeekable();
var sourceStream = new SourceStream(
strms[0],
i => i < strms.Count ? strms[i] : null,
Expand Down
12 changes: 4 additions & 8 deletions src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ public static IWritableArchive<ZipWriterOptions> OpenArchive(
ReaderOptions? readerOptions = null
)
{
streams.NotNull(nameof(streams));
var strms = streams;
var strms = streams.RequireReadable();
strms.RequireSeekable();
return new ZipArchive(
new SourceStream(
strms[0],

Copilot AI Apr 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenArchive(IReadOnlyList<Stream>) indexes strms[0] without guarding against an empty stream list, which will throw an IndexOutOfRangeException. Add an explicit Count == 0 check and throw a more meaningful exception (consistent with ArchiveFactory.OpenArchive's "No streams" behavior).

Copilot uses AI. Check for mistakes.
Expand All @@ -83,12 +83,8 @@ public static IWritableArchive<ZipWriterOptions> OpenArchive(
ReaderOptions? readerOptions = null
)
{
stream.NotNull(nameof(stream));

if (stream is not { CanSeek: true })
{
throw new ArgumentException("Stream must be seekable", nameof(stream));
}
stream.RequireReadable();
stream.RequireSeekable();

return new ZipArchive(
new SourceStream(stream, i => null, readerOptions ?? ReaderOptions.ForExternalStream)
Expand Down
10 changes: 5 additions & 5 deletions src/SharpCompress/Readers/Ace/AceReader.Factory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public partial class AceReader
/// <returns>An AceReader instance.</returns>
public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null)
{
stream.NotNull(nameof(stream));
stream.RequireReadable();
return new SingleVolumeAceReader(stream, readerOptions ?? ReaderOptions.ForExternalStream);
}

Expand All @@ -31,8 +31,8 @@ public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = n
/// <returns></returns>
public static IReader OpenReader(IEnumerable<Stream> streams, ReaderOptions? options = null)
{
streams.NotNull(nameof(streams));
return new MultiVolumeAceReader(streams, options ?? ReaderOptions.ForExternalStream);
var streamArray = streams.RequireReadable();
return new MultiVolumeAceReader(streamArray, options ?? ReaderOptions.ForExternalStream);
}

public static ValueTask<IAsyncReader> OpenAsyncReader(
Expand Down Expand Up @@ -61,8 +61,8 @@ public static IAsyncReader OpenAsyncReader(
ReaderOptions? options = null
)
{
streams.NotNull(nameof(streams));
return new MultiVolumeAceReader(streams, options ?? ReaderOptions.ForExternalStream);
var streamArray = streams.RequireReadable();
return new MultiVolumeAceReader(streamArray, options ?? ReaderOptions.ForExternalStream);
}

public static ValueTask<IAsyncReader> OpenAsyncReader(
Expand Down
2 changes: 1 addition & 1 deletion src/SharpCompress/Readers/Ace/SingleVolumeAceReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal class SingleVolumeAceReader : AceReader
internal SingleVolumeAceReader(Stream stream, ReaderOptions options)
: base(options)
{
stream.NotNull(nameof(stream));
stream.RequireReadable();
_stream = stream;
}

Expand Down
2 changes: 1 addition & 1 deletion src/SharpCompress/Readers/Arc/ArcReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ private ArcReader(Stream stream, ReaderOptions options)
/// <returns></returns>
public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null)
{
stream.NotNull(nameof(stream));
stream.RequireReadable();
return new ArcReader(stream, readerOptions ?? ReaderOptions.ForExternalStream);
}

Expand Down
6 changes: 3 additions & 3 deletions src/SharpCompress/Readers/Arj/ArjReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ internal ArjReader(ReaderOptions options)
/// <returns></returns>
public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null)
{
stream.NotNull(nameof(stream));
stream.RequireReadable();
return new SingleVolumeArjReader(stream, readerOptions ?? ReaderOptions.ForExternalStream);
}

Expand All @@ -43,8 +43,8 @@ public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = n
/// <returns></returns>
public static IReader OpenReader(IEnumerable<Stream> streams, ReaderOptions? options = null)
{
streams.NotNull(nameof(streams));
return new MultiVolumeArjReader(streams, options ?? ReaderOptions.ForExternalStream);
var streamArray = streams.RequireReadable();
return new MultiVolumeArjReader(streamArray, options ?? ReaderOptions.ForExternalStream);
}

protected abstract void ValidateArchive(ArjVolume archive);
Expand Down
2 changes: 1 addition & 1 deletion src/SharpCompress/Readers/Arj/SingleVolumeArjReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal class SingleVolumeArjReader : ArjReader
internal SingleVolumeArjReader(Stream stream, ReaderOptions options)
: base(options)
{
stream.NotNull(nameof(stream));
stream.RequireReadable();
_stream = stream;
}

Expand Down
2 changes: 1 addition & 1 deletion src/SharpCompress/Readers/GZip/GZipReader.Factory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public static IReader OpenReader(FileInfo fileInfo, ReaderOptions? readerOptions

public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null)
{
stream.NotNull(nameof(stream));
stream.RequireReadable();
return new GZipReader(stream, readerOptions ?? ReaderOptions.ForExternalStream);
}
}
2 changes: 1 addition & 1 deletion src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public static IReader OpenReader(FileInfo fileInfo, ReaderOptions? readerOptions

public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null)
{
stream.NotNull(nameof(stream));
stream.RequireReadable();
return new LzwReader(stream, readerOptions ?? ReaderOptions.ForExternalStream);
}
}
6 changes: 3 additions & 3 deletions src/SharpCompress/Readers/Rar/RarReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public static IReader OpenReader(IEnumerable<FileInfo> fileInfos, ReaderOptions?
/// <returns></returns>
public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null)
{
stream.NotNull(nameof(stream));
stream.RequireReadable();
return new SingleVolumeRarReader(stream, readerOptions ?? ReaderOptions.ForExternalStream);
}

Expand All @@ -83,8 +83,8 @@ public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = n
/// <returns></returns>
public static IReader OpenReader(IEnumerable<Stream> streams, ReaderOptions? options = null)
{
streams.NotNull(nameof(streams));
return new MultiVolumeRarReader(streams, options ?? ReaderOptions.ForExternalStream);
var streamArray = streams.RequireReadable();
return new MultiVolumeRarReader(streamArray, options ?? ReaderOptions.ForExternalStream);
}

protected override IEnumerable<RarReaderEntry> GetEntries(Stream stream)
Expand Down
2 changes: 1 addition & 1 deletion src/SharpCompress/Readers/ReaderFactory.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public static async ValueTask<IAsyncReader> OpenAsyncReader(
CancellationToken cancellationToken = default
)
{
stream.NotNull(nameof(stream));
stream.RequireReadable();
options ??= ReaderOptions.ForExternalStream;

var sharpCompressStream = SharpCompressStream.Create(
Expand Down
2 changes: 1 addition & 1 deletion src/SharpCompress/Readers/ReaderFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public static IReader OpenReader(FileInfo fileInfo, ReaderOptions? options = nul
/// <returns></returns>
public static IReader OpenReader(Stream stream, ReaderOptions? options = null)
{
stream.NotNull(nameof(stream));
stream.RequireReadable();
options ??= ReaderOptions.ForExternalStream;

var sharpCompressStream = SharpCompressStream.Create(
Expand Down
2 changes: 1 addition & 1 deletion src/SharpCompress/Readers/Tar/TarReader.Factory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ public static IReader OpenReader(FileInfo fileInfo, ReaderOptions? readerOptions
/// <returns></returns>
public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null)
{
stream.NotNull(nameof(stream));
stream.RequireReadable();
readerOptions ??= ReaderOptions.ForExternalStream;
var sharpCompressStream = SharpCompressStream.Create(
stream,
Expand Down
4 changes: 2 additions & 2 deletions src/SharpCompress/Readers/Zip/ZipReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private ZipReader(Stream stream, ReaderOptions options, IEnumerable<ZipEntry> en
/// <returns></returns>
public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null)
{
stream.NotNull(nameof(stream));
stream.RequireReadable();
return new ZipReader(stream, readerOptions ?? ReaderOptions.ForExternalStream);
}

Expand All @@ -57,7 +57,7 @@ public static IReader OpenReader(
IEnumerable<ZipEntry> entries
)
{
stream.NotNull(nameof(stream));
stream.RequireReadable();
return new ZipReader(stream, options ?? ReaderOptions.ForExternalStream, entries);
}

Expand Down
Loading
Loading