diff --git a/.gitignore b/.gitignore index 66147659..80f4154a 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ profiler-snapshots/ .DS_Store *.snupkg benchmark-results/ +/.opencode diff --git a/src/SharpCompress/Archives/ArchiveFactory.Async.cs b/src/SharpCompress/Archives/ArchiveFactory.Async.cs index fde9a93d..84bb671d 100644 --- a/src/SharpCompress/Archives/ArchiveFactory.Async.cs +++ b/src/SharpCompress/Archives/ArchiveFactory.Async.cs @@ -92,13 +92,7 @@ public static partial class ArchiveFactory ) { cancellationToken.ThrowIfCancellationRequested(); - streams.NotNull(nameof(streams)); - var streamsArray = streams; - if (streamsArray.Count == 0) - { - throw new ArchiveOperationException("No streams"); - } - + var streamsArray = streams.RequireReadable().RequireSeekable().ToList(); var firstStream = streamsArray[0]; if (streamsArray.Count == 1) { @@ -143,11 +137,8 @@ public static partial class ArchiveFactory ) 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(); diff --git a/src/SharpCompress/Archives/ArchiveFactory.cs b/src/SharpCompress/Archives/ArchiveFactory.cs index ec044e0e..34cc5bb1 100644 --- a/src/SharpCompress/Archives/ArchiveFactory.cs +++ b/src/SharpCompress/Archives/ArchiveFactory.cs @@ -73,8 +73,7 @@ public static partial class ArchiveFactory public static IArchive OpenArchive(IReadOnlyList streams, ReaderOptions? options = null) { - streams.NotNull(nameof(streams)); - var streamsArray = streams; + var streamsArray = streams.RequireReadable().RequireSeekable().ToList(); if (streamsArray.Count == 0) { throw new ArchiveOperationException("No streams"); @@ -121,11 +120,8 @@ public static partial class ArchiveFactory public static T FindFactory(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(); @@ -160,12 +156,8 @@ public static partial class ArchiveFactory 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; @@ -199,12 +191,8 @@ public static partial class ArchiveFactory 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; diff --git a/src/SharpCompress/Archives/GZip/GZipArchive.Factory.cs b/src/SharpCompress/Archives/GZip/GZipArchive.Factory.cs index 9dad1ae8..2f5e5e33 100644 --- a/src/SharpCompress/Archives/GZip/GZipArchive.Factory.cs +++ b/src/SharpCompress/Archives/GZip/GZipArchive.Factory.cs @@ -76,8 +76,7 @@ public partial class GZipArchive ReaderOptions? readerOptions = null ) { - streams.NotNull(nameof(streams)); - var strms = streams; + var strms = streams.RequireReadable().RequireSeekable().ToList(); return new GZipArchive( new SourceStream( strms[0], @@ -92,12 +91,8 @@ public partial class GZipArchive 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) diff --git a/src/SharpCompress/Archives/Rar/RarArchive.Factory.cs b/src/SharpCompress/Archives/Rar/RarArchive.Factory.cs index df820e2f..2c333c5c 100644 --- a/src/SharpCompress/Archives/Rar/RarArchive.Factory.cs +++ b/src/SharpCompress/Archives/Rar/RarArchive.Factory.cs @@ -58,12 +58,8 @@ public partial class RarArchive 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) @@ -91,8 +87,7 @@ public partial class RarArchive ReaderOptions? readerOptions = null ) { - streams.NotNull(nameof(streams)); - var strms = streams; + var strms = streams.RequireReadable().RequireSeekable().ToList(); return new RarArchive( new SourceStream( strms[0], diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.Factory.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.Factory.cs index df7fa8c4..a338e363 100644 --- a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.Factory.cs +++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.Factory.cs @@ -71,8 +71,7 @@ public partial class SevenZipArchive ReaderOptions? readerOptions = null ) { - streams.NotNull(nameof(streams)); - var strms = streams; + var strms = streams.RequireReadable().RequireSeekable().ToList(); return new SevenZipArchive( new SourceStream( strms[0], @@ -84,12 +83,8 @@ public partial class SevenZipArchive 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) diff --git a/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs b/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs index e1464dbf..d166f8c8 100644 --- a/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs +++ b/src/SharpCompress/Archives/Tar/TarArchive.Factory.cs @@ -66,8 +66,7 @@ public partial class TarArchive ReaderOptions? readerOptions = null ) { - streams.NotNull(nameof(streams)); - var strms = streams; + var strms = streams.RequireReadable().RequireSeekable().ToList(); var sourceStream = new SourceStream( strms[0], i => i < strms.Count ? strms[i] : null, @@ -86,12 +85,8 @@ public partial class TarArchive 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); } @@ -102,7 +97,8 @@ public partial class TarArchive CancellationToken cancellationToken = default ) { - stream.NotNull(nameof(stream)); + stream.RequireReadable(); + stream.RequireSeekable(); var sourceStream = new SourceStream( stream, i => null, @@ -158,8 +154,7 @@ public partial class TarArchive ) { cancellationToken.ThrowIfCancellationRequested(); - streams.NotNull(nameof(streams)); - var strms = streams; + var strms = streams.RequireReadable().RequireSeekable().ToList(); var sourceStream = new SourceStream( strms[0], i => i < strms.Count ? strms[i] : null, diff --git a/src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs b/src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs index bdd18669..1e02ad6f 100644 --- a/src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs +++ b/src/SharpCompress/Archives/Zip/ZipArchive.Factory.cs @@ -67,8 +67,7 @@ public partial class ZipArchive ReaderOptions? readerOptions = null ) { - streams.NotNull(nameof(streams)); - var strms = streams; + var strms = streams.RequireReadable().RequireSeekable().ToList(); return new ZipArchive( new SourceStream( strms[0], @@ -83,12 +82,8 @@ public partial class ZipArchive 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) diff --git a/src/SharpCompress/Readers/Ace/AceReader.Factory.cs b/src/SharpCompress/Readers/Ace/AceReader.Factory.cs index 5977e8de..98c3124a 100644 --- a/src/SharpCompress/Readers/Ace/AceReader.Factory.cs +++ b/src/SharpCompress/Readers/Ace/AceReader.Factory.cs @@ -19,7 +19,7 @@ public partial class AceReader /// An AceReader instance. public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null) { - stream.NotNull(nameof(stream)); + stream.RequireReadable(); return new SingleVolumeAceReader(stream, readerOptions ?? ReaderOptions.ForExternalStream); } @@ -31,8 +31,8 @@ public partial class AceReader /// public static IReader OpenReader(IEnumerable 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 OpenAsyncReader( @@ -61,8 +61,8 @@ public partial class AceReader 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 OpenAsyncReader( diff --git a/src/SharpCompress/Readers/Ace/SingleVolumeAceReader.cs b/src/SharpCompress/Readers/Ace/SingleVolumeAceReader.cs index ce42c6e1..ba782d23 100644 --- a/src/SharpCompress/Readers/Ace/SingleVolumeAceReader.cs +++ b/src/SharpCompress/Readers/Ace/SingleVolumeAceReader.cs @@ -12,7 +12,7 @@ internal class SingleVolumeAceReader : AceReader internal SingleVolumeAceReader(Stream stream, ReaderOptions options) : base(options) { - stream.NotNull(nameof(stream)); + stream.RequireReadable(); _stream = stream; } diff --git a/src/SharpCompress/Readers/Arc/ArcReader.cs b/src/SharpCompress/Readers/Arc/ArcReader.cs index c1b53366..e2a8303d 100644 --- a/src/SharpCompress/Readers/Arc/ArcReader.cs +++ b/src/SharpCompress/Readers/Arc/ArcReader.cs @@ -24,7 +24,7 @@ public partial class ArcReader : AbstractReader /// public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null) { - stream.NotNull(nameof(stream)); + stream.RequireReadable(); return new ArcReader(stream, readerOptions ?? ReaderOptions.ForExternalStream); } diff --git a/src/SharpCompress/Readers/Arj/ArjReader.cs b/src/SharpCompress/Readers/Arj/ArjReader.cs index a0c4899c..79389b87 100644 --- a/src/SharpCompress/Readers/Arj/ArjReader.cs +++ b/src/SharpCompress/Readers/Arj/ArjReader.cs @@ -31,7 +31,7 @@ public abstract partial class ArjReader : AbstractReader /// public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null) { - stream.NotNull(nameof(stream)); + stream.RequireReadable(); return new SingleVolumeArjReader(stream, readerOptions ?? ReaderOptions.ForExternalStream); } @@ -43,8 +43,8 @@ public abstract partial class ArjReader : AbstractReader /// public static IReader OpenReader(IEnumerable 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); diff --git a/src/SharpCompress/Readers/Arj/SingleVolumeArjReader.cs b/src/SharpCompress/Readers/Arj/SingleVolumeArjReader.cs index 71eb46e4..0128f60e 100644 --- a/src/SharpCompress/Readers/Arj/SingleVolumeArjReader.cs +++ b/src/SharpCompress/Readers/Arj/SingleVolumeArjReader.cs @@ -12,7 +12,7 @@ internal class SingleVolumeArjReader : ArjReader internal SingleVolumeArjReader(Stream stream, ReaderOptions options) : base(options) { - stream.NotNull(nameof(stream)); + stream.RequireReadable(); _stream = stream; } diff --git a/src/SharpCompress/Readers/GZip/GZipReader.Factory.cs b/src/SharpCompress/Readers/GZip/GZipReader.Factory.cs index bd593f20..a6bca9f6 100644 --- a/src/SharpCompress/Readers/GZip/GZipReader.Factory.cs +++ b/src/SharpCompress/Readers/GZip/GZipReader.Factory.cs @@ -55,7 +55,7 @@ public partial class GZipReader public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null) { - stream.NotNull(nameof(stream)); + stream.RequireReadable(); return new GZipReader(stream, readerOptions ?? ReaderOptions.ForExternalStream); } } diff --git a/src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs b/src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs index e2166e37..a1535c89 100644 --- a/src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs +++ b/src/SharpCompress/Readers/Lzw/LzwReader.Factory.cs @@ -55,7 +55,7 @@ public partial class LzwReader public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null) { - stream.NotNull(nameof(stream)); + stream.RequireReadable(); return new LzwReader(stream, readerOptions ?? ReaderOptions.ForExternalStream); } } diff --git a/src/SharpCompress/Readers/Rar/RarReader.cs b/src/SharpCompress/Readers/Rar/RarReader.cs index 81a5457c..43925d64 100644 --- a/src/SharpCompress/Readers/Rar/RarReader.cs +++ b/src/SharpCompress/Readers/Rar/RarReader.cs @@ -71,7 +71,7 @@ public abstract partial class RarReader : AbstractReader public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null) { - stream.NotNull(nameof(stream)); + stream.RequireReadable(); return new SingleVolumeRarReader(stream, readerOptions ?? ReaderOptions.ForExternalStream); } @@ -83,8 +83,8 @@ public abstract partial class RarReader : AbstractReader public static IReader OpenReader(IEnumerable 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 GetEntries(Stream stream) diff --git a/src/SharpCompress/Readers/ReaderFactory.Async.cs b/src/SharpCompress/Readers/ReaderFactory.Async.cs index 80388577..72bd7b09 100644 --- a/src/SharpCompress/Readers/ReaderFactory.Async.cs +++ b/src/SharpCompress/Readers/ReaderFactory.Async.cs @@ -56,7 +56,7 @@ public static partial class ReaderFactory CancellationToken cancellationToken = default ) { - stream.NotNull(nameof(stream)); + stream.RequireReadable(); options ??= ReaderOptions.ForExternalStream; var sharpCompressStream = SharpCompressStream.Create( diff --git a/src/SharpCompress/Readers/ReaderFactory.cs b/src/SharpCompress/Readers/ReaderFactory.cs index 2a84913c..72c4dd71 100644 --- a/src/SharpCompress/Readers/ReaderFactory.cs +++ b/src/SharpCompress/Readers/ReaderFactory.cs @@ -29,7 +29,7 @@ public static partial class ReaderFactory /// public static IReader OpenReader(Stream stream, ReaderOptions? options = null) { - stream.NotNull(nameof(stream)); + stream.RequireReadable(); options ??= ReaderOptions.ForExternalStream; var sharpCompressStream = SharpCompressStream.Create( diff --git a/src/SharpCompress/Readers/Tar/TarReader.Factory.cs b/src/SharpCompress/Readers/Tar/TarReader.Factory.cs index aae20bb4..aa13c779 100644 --- a/src/SharpCompress/Readers/Tar/TarReader.Factory.cs +++ b/src/SharpCompress/Readers/Tar/TarReader.Factory.cs @@ -170,7 +170,7 @@ public partial class TarReader /// public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null) { - stream.NotNull(nameof(stream)); + stream.RequireReadable(); readerOptions ??= ReaderOptions.ForExternalStream; var sharpCompressStream = SharpCompressStream.Create( stream, diff --git a/src/SharpCompress/Readers/Zip/ZipReader.cs b/src/SharpCompress/Readers/Zip/ZipReader.cs index e2019de6..a9ca5c50 100644 --- a/src/SharpCompress/Readers/Zip/ZipReader.cs +++ b/src/SharpCompress/Readers/Zip/ZipReader.cs @@ -47,7 +47,7 @@ public partial class ZipReader : AbstractReader /// public static IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null) { - stream.NotNull(nameof(stream)); + stream.RequireReadable(); return new ZipReader(stream, readerOptions ?? ReaderOptions.ForExternalStream); } @@ -57,7 +57,7 @@ public partial class ZipReader : AbstractReader IEnumerable entries ) { - stream.NotNull(nameof(stream)); + stream.RequireReadable(); return new ZipReader(stream, options ?? ReaderOptions.ForExternalStream, entries); } diff --git a/src/SharpCompress/StreamValidationExtensions.cs b/src/SharpCompress/StreamValidationExtensions.cs new file mode 100644 index 00000000..28bd9116 --- /dev/null +++ b/src/SharpCompress/StreamValidationExtensions.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace SharpCompress; + +internal static class StreamValidationExtensions +{ + internal static void RequireReadable(this Stream stream) + { + stream.NotNull(nameof(stream)); + + if (!stream.CanRead) + { + throw new ArgumentException("Stream must be readable", nameof(stream)); + } + } + + internal static void RequireSeekable(this Stream stream) + { + stream.NotNull(nameof(stream)); + + if (!stream.CanSeek) + { + throw new ArgumentException("Stream must be seekable", nameof(stream)); + } + } + + internal static void RequireWritable(this Stream stream) + { + stream.NotNull(nameof(stream)); + + if (!stream.CanWrite) + { + throw new ArgumentException("Stream must be writable", nameof(stream)); + } + } + + internal static IEnumerable RequireSeekable(this IEnumerable streams) + { + foreach (var stream in streams) + { + stream.RequireSeekable(); + yield return stream; + } + } + + internal static IEnumerable RequireReadable(this IEnumerable streams) + { + foreach (var stream in streams) + { + stream.RequireReadable(); + yield return stream; + } + } +} diff --git a/src/SharpCompress/Writers/GZip/GZipWriter.Factory.cs b/src/SharpCompress/Writers/GZip/GZipWriter.Factory.cs index f4f2b902..cae0b91d 100644 --- a/src/SharpCompress/Writers/GZip/GZipWriter.Factory.cs +++ b/src/SharpCompress/Writers/GZip/GZipWriter.Factory.cs @@ -22,7 +22,7 @@ public partial class GZipWriter : IWriterOpenable public static IWriter OpenWriter(Stream stream, GZipWriterOptions writerOptions) { - stream.NotNull(nameof(stream)); + stream.RequireWritable(); return new GZipWriter(stream, writerOptions); } diff --git a/src/SharpCompress/Writers/SevenZip/SevenZipWriter.Factory.cs b/src/SharpCompress/Writers/SevenZip/SevenZipWriter.Factory.cs index e84d7401..1191a83a 100644 --- a/src/SharpCompress/Writers/SevenZip/SevenZipWriter.Factory.cs +++ b/src/SharpCompress/Writers/SevenZip/SevenZipWriter.Factory.cs @@ -36,7 +36,7 @@ public partial class SevenZipWriter : IWriterOpenable /// public static IWriter OpenWriter(Stream stream, SevenZipWriterOptions writerOptions) { - stream.NotNull(nameof(stream)); + stream.RequireWritable(); return new SevenZipWriter(stream, writerOptions); } diff --git a/src/SharpCompress/Writers/Tar/TarWriter.Factory.cs b/src/SharpCompress/Writers/Tar/TarWriter.Factory.cs index b00ed13e..7613374b 100644 --- a/src/SharpCompress/Writers/Tar/TarWriter.Factory.cs +++ b/src/SharpCompress/Writers/Tar/TarWriter.Factory.cs @@ -22,7 +22,7 @@ public partial class TarWriter : IWriterOpenable public static IWriter OpenWriter(Stream stream, TarWriterOptions writerOptions) { - stream.NotNull(nameof(stream)); + stream.RequireWritable(); return new TarWriter(stream, writerOptions); } diff --git a/src/SharpCompress/Writers/WriterFactory.cs b/src/SharpCompress/Writers/WriterFactory.cs index 48ef1d47..847766f9 100644 --- a/src/SharpCompress/Writers/WriterFactory.cs +++ b/src/SharpCompress/Writers/WriterFactory.cs @@ -75,6 +75,8 @@ public static class WriterFactory IWriterOptions writerOptions ) { + stream.RequireWritable(); + var factory = Factories .Factory.Factories.OfType() .FirstOrDefault(item => item.KnownArchiveType == archiveType); @@ -102,6 +104,8 @@ public static class WriterFactory CancellationToken cancellationToken = default ) { + stream.RequireWritable(); + var factory = Factories .Factory.Factories.OfType() .FirstOrDefault(item => item.KnownArchiveType == archiveType); diff --git a/src/SharpCompress/Writers/Zip/ZipWriter.Factory.cs b/src/SharpCompress/Writers/Zip/ZipWriter.Factory.cs index b6667842..825de870 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriter.Factory.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriter.Factory.cs @@ -22,7 +22,7 @@ public partial class ZipWriter : IWriterOpenable public static IWriter OpenWriter(Stream stream, ZipWriterOptions writerOptions) { - stream.NotNull(nameof(stream)); + stream.RequireWritable(); return new ZipWriter(stream, writerOptions); } diff --git a/src/SharpCompress/packages.lock.json b/src/SharpCompress/packages.lock.json index a401c702..e82196f8 100644 --- a/src/SharpCompress/packages.lock.json +++ b/src/SharpCompress/packages.lock.json @@ -268,9 +268,9 @@ "net10.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[10.0.0, )", - "resolved": "10.0.0", - "contentHash": "kICGrGYEzCNI3wPzfEXcwNHgTvlvVn9yJDhSdRK+oZQy4jvYH529u7O0xf5ocQKzOMjfS07+3z9PKRIjrFMJDA==" + "requested": "[10.0.6, )", + "resolved": "10.0.6", + "contentHash": "QKuvS0LWX4fjFqeDkyM7Kqt8P3wYTiPD4nwU+9y59n0sCiG714fxDgbbN82vDnzq89AF/PiHl92TP2C4aFDUQA==" }, "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct", @@ -400,9 +400,9 @@ "net8.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[8.0.22, )", - "resolved": "8.0.22", - "contentHash": "MhcMithKEiyyNkD2ZfbDZPmcOdi0GheGfg8saEIIEfD/fol3iHmcV8TsZkD4ZYz5gdUuoX4YtlVySUU7Sxl9SQ==" + "requested": "[8.0.26, )", + "resolved": "8.0.26", + "contentHash": "o7/yVssM2r9Wyln2s9edBd5ANZXqdSdBI+g7JqXkyJmXrhs2WsJp25K5yPnYrTgdKBCjKB8bg+O2oew4sgzFaA==" }, "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct", diff --git a/tests/SharpCompress.Test/ArchiveFactoryTests.cs b/tests/SharpCompress.Test/ArchiveFactoryTests.cs index 96249f8e..d6326bad 100644 --- a/tests/SharpCompress.Test/ArchiveFactoryTests.cs +++ b/tests/SharpCompress.Test/ArchiveFactoryTests.cs @@ -1,9 +1,11 @@ +using System; using System.IO; using System.Text; using System.Threading.Tasks; using SharpCompress.Archives; using SharpCompress.Common; using SharpCompress.Factories; +using SharpCompress.Test.Mocks; using Xunit; namespace SharpCompress.Test; @@ -61,6 +63,26 @@ public class ArchiveFactoryTests : TestBase Assert.Equal(startPosition, stream.Position); } + [Fact] + public void OpenArchive_StreamCollection_Throws_On_NonSeekable_Stream() + { + using var nonSeekable = new ForwardOnlyStream(new MemoryStream()); + using var seekable = new MemoryStream(); + + Assert.Throws(() => ArchiveFactory.OpenArchive([nonSeekable, seekable])); + } + + [Fact] + public async ValueTask OpenAsyncArchive_StreamCollection_Throws_On_NonSeekable_Stream() + { + using var nonSeekable = new ForwardOnlyStream(new MemoryStream()); + using var seekable = new MemoryStream(); + + await Assert.ThrowsAsync(() => + ArchiveFactory.OpenAsyncArchive([nonSeekable, seekable]).AsTask() + ); + } + [Fact] public async ValueTask FindFactoryAsync_InvalidData_ThrowsArchiveOperationException() { @@ -71,6 +93,24 @@ public class ArchiveFactoryTests : TestBase ); } + [Fact] + public void OpenArchive_Stream_Throws_On_Unreadable_Stream() + { + using var unreadable = new TestStream(new MemoryStream(), false, true, true); + + Assert.Throws(() => ArchiveFactory.OpenArchive(unreadable)); + } + + [Fact] + public async ValueTask OpenAsyncArchive_Stream_Throws_On_Unreadable_Stream() + { + using var unreadable = new TestStream(new MemoryStream(), false, true, true); + + await Assert.ThrowsAsync(() => + ArchiveFactory.OpenAsyncArchive(unreadable).AsTask() + ); + } + [Theory] [InlineData("Zip.deflate.zip", ArchiveType.Zip)] [InlineData("Tar.noEmptyDirs.tar", ArchiveType.Tar)] diff --git a/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs b/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs index a33256a6..5f9f5094 100644 --- a/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs +++ b/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs @@ -5,6 +5,7 @@ using SharpCompress.Archives; using SharpCompress.Archives.GZip; using SharpCompress.Archives.Tar; using SharpCompress.Common; +using SharpCompress.Test.Mocks; using SharpCompress.Writers.GZip; using Xunit; @@ -127,6 +128,23 @@ public class GZipArchiveTests : ArchiveTests Assert.Equal(archive.Type, ArchiveType.GZip); } + [Fact] + public void GZipArchive_StreamCollection_Throws_On_NonSeekable_Stream() + { + using var nonSeekable = new ForwardOnlyStream(new MemoryStream()); + using var seekable = new MemoryStream(); + + Assert.Throws(() => GZipArchive.OpenArchive([nonSeekable, seekable])); + } + + [Fact] + public void GZipArchive_Stream_Throws_On_Unreadable_Stream() + { + using var unreadable = new TestStream(new MemoryStream(), false, true, true); + + Assert.Throws(() => GZipArchive.OpenArchive(unreadable)); + } + [Fact] public void GZip_Archive_NonSeekableStream() { diff --git a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs index 20b5faa0..c4ef386c 100644 --- a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs +++ b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs @@ -122,6 +122,23 @@ public class RarArchiveTests : ArchiveTests [Fact] public void Rar_ArchiveStreamRead() => ArchiveStreamRead("Rar.rar"); + [Fact] + public void RarArchive_StreamCollection_Throws_On_NonSeekable_Stream() + { + using var nonSeekable = new ForwardOnlyStream(new MemoryStream()); + using var seekable = new MemoryStream(); + + Assert.Throws(() => RarArchive.OpenArchive([nonSeekable, seekable])); + } + + [Fact] + public void RarArchive_Stream_Throws_On_Unreadable_Stream() + { + using var unreadable = new TestStream(new MemoryStream(), false, true, true); + + Assert.Throws(() => RarArchive.OpenArchive(unreadable)); + } + [Fact] public void Rar5_ArchiveStreamRead() => ArchiveStreamRead("Rar5.rar"); diff --git a/tests/SharpCompress.Test/ReaderFactoryTests.cs b/tests/SharpCompress.Test/ReaderFactoryTests.cs new file mode 100644 index 00000000..2c5236c8 --- /dev/null +++ b/tests/SharpCompress.Test/ReaderFactoryTests.cs @@ -0,0 +1,41 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using SharpCompress.Readers; +using SharpCompress.Readers.Rar; +using SharpCompress.Test.Mocks; +using Xunit; + +namespace SharpCompress.Test; + +public class ReaderFactoryTests +{ + [Fact] + public void OpenReader_Stream_Throws_On_Unreadable_Stream() + { + using var unreadable = new TestStream(new MemoryStream(), false, true, true); + + Assert.Throws(() => ReaderFactory.OpenReader(unreadable)); + } + + [Fact] + public async ValueTask OpenAsyncReader_Stream_Throws_On_Unreadable_Stream() + { + using var unreadable = new TestStream(new MemoryStream(), false, true, true); + + await Assert.ThrowsAsync(() => + ReaderFactory.OpenAsyncReader(unreadable).AsTask() + ); + } + + [Fact] + public void RarReader_StreamCollection_Throws_On_Unreadable_Stream() + { + using var unreadable = new TestStream(new MemoryStream(), false, true, true); + using var readable = new MemoryStream(); + + Assert.Throws(() => + RarReader.OpenReader([unreadable, readable]).MoveToNextEntry() + ); + } +} diff --git a/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs b/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs index e3016d96..0fc86c3e 100644 --- a/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs +++ b/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs @@ -7,6 +7,7 @@ using SharpCompress.Common; using SharpCompress.Common.SevenZip; using SharpCompress.Factories; using SharpCompress.Readers; +using SharpCompress.Test.Mocks; using Xunit; namespace SharpCompress.Test.SevenZip; @@ -25,6 +26,25 @@ public class SevenZipArchiveTests : ArchiveTests [Fact] public void SevenZipArchive_LZMA_PathRead() => ArchiveFileRead("7Zip.LZMA.7z"); + [Fact] + public void SevenZipArchive_StreamCollection_Throws_On_NonSeekable_Stream() + { + using var nonSeekable = new ForwardOnlyStream(new MemoryStream()); + using var seekable = new MemoryStream(); + + Assert.Throws(() => + SevenZipArchive.OpenArchive([nonSeekable, seekable]) + ); + } + + [Fact] + public void SevenZipArchive_Stream_Throws_On_Unreadable_Stream() + { + using var unreadable = new TestStream(new MemoryStream(), false, true, true); + + Assert.Throws(() => SevenZipArchive.OpenArchive(unreadable)); + } + [Fact] public void SevenZipArchive_LZMAAES_StreamRead() => ArchiveStreamRead( diff --git a/tests/SharpCompress.Test/Tar/TarArchiveAsyncTests.cs b/tests/SharpCompress.Test/Tar/TarArchiveAsyncTests.cs index 30b511fa..a2c06516 100644 --- a/tests/SharpCompress.Test/Tar/TarArchiveAsyncTests.cs +++ b/tests/SharpCompress.Test/Tar/TarArchiveAsyncTests.cs @@ -22,6 +22,26 @@ public class TarArchiveAsyncTests : ArchiveTests [Fact] public async ValueTask TarArchiveStreamRead_Async() => await ArchiveStreamReadAsync("Tar.tar"); + [Fact] + public async ValueTask TarArchiveOpenAsyncStream_Throws_On_NonSeekable_Stream() + { + using var stream = new ForwardOnlyStream(new MemoryStream()); + + await Assert.ThrowsAsync(() => + TarArchive.OpenAsyncArchive(stream).AsTask() + ); + } + + [Fact] + public async ValueTask TarArchiveOpenAsyncStream_Throws_On_Unreadable_Stream() + { + using var stream = new TestStream(new MemoryStream(), false, true, true); + + await Assert.ThrowsAsync(() => + TarArchive.OpenAsyncArchive(stream).AsTask() + ); + } + [Fact] public async ValueTask Tar_FileName_Exactly_100_Characters_Async() { diff --git a/tests/SharpCompress.Test/Tar/TarArchiveTests.cs b/tests/SharpCompress.Test/Tar/TarArchiveTests.cs index ebb721f5..5f522e7c 100644 --- a/tests/SharpCompress.Test/Tar/TarArchiveTests.cs +++ b/tests/SharpCompress.Test/Tar/TarArchiveTests.cs @@ -34,6 +34,28 @@ public class TarArchiveTests : ArchiveTests Assert.Throws(() => ArchiveFactory.OpenArchive(stream)); } + [Fact] + public void TarArchiveStreamRead_Throws_On_Unreadable_Stream() + { + using var unreadable = new TestStream( + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")), + false, + true, + true + ); + + Assert.Throws(() => TarArchive.OpenArchive(unreadable)); + } + + [Fact] + public void TarArchive_StreamCollection_Throws_On_NonSeekable_Stream() + { + using var nonSeekable = new ForwardOnlyStream(new MemoryStream()); + using var seekable = new MemoryStream(); + + Assert.Throws(() => TarArchive.OpenArchive([nonSeekable, seekable])); + } + [Fact] public void Tar_FileName_Exactly_100_Characters() { diff --git a/tests/SharpCompress.Test/WriterFactoryTests.cs b/tests/SharpCompress.Test/WriterFactoryTests.cs new file mode 100644 index 00000000..ca7a45a5 --- /dev/null +++ b/tests/SharpCompress.Test/WriterFactoryTests.cs @@ -0,0 +1,34 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using SharpCompress.Common; +using SharpCompress.Test.Mocks; +using SharpCompress.Writers; +using Xunit; + +namespace SharpCompress.Test; + +public class WriterFactoryTests +{ + [Fact] + public void OpenWriter_Stream_Throws_On_Unwritable_Stream() + { + using var unwritable = new TestStream(new MemoryStream(), true, false, true); + + Assert.Throws(() => + WriterFactory.OpenWriter(unwritable, ArchiveType.Zip, WriterOptions.ForZip()) + ); + } + + [Fact] + public async ValueTask OpenAsyncWriter_Stream_Throws_On_Unwritable_Stream() + { + using var unwritable = new TestStream(new MemoryStream(), true, false, true); + + await Assert.ThrowsAsync(() => + WriterFactory + .OpenAsyncWriter(unwritable, ArchiveType.Zip, WriterOptions.ForZip()) + .AsTask() + ); + } +} diff --git a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs index 82192b22..ca80917f 100644 --- a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs @@ -7,6 +7,7 @@ using SharpCompress.Archives.Zip; using SharpCompress.Common; using SharpCompress.Common.Zip; using SharpCompress.Readers; +using SharpCompress.Test.Mocks; using SharpCompress.Writers; using SharpCompress.Writers.Zip; using Xunit; @@ -28,6 +29,23 @@ public class ZipArchiveTests : ArchiveTests [Fact] public void Zip_BZip2_ArchiveStreamRead() => ArchiveStreamRead("Zip.bzip2.zip"); + [Fact] + public void ZipArchive_StreamCollection_Throws_On_NonSeekable_Stream() + { + using var nonSeekable = new NonSeekableMemoryStream(); + using var seekable = new MemoryStream(); + + Assert.Throws(() => ZipArchive.OpenArchive([nonSeekable, seekable])); + } + + [Fact] + public void ZipArchive_Stream_Throws_On_Unreadable_Stream() + { + using var unreadable = new TestStream(new MemoryStream(), false, true, true); + + Assert.Throws(() => ZipArchive.OpenArchive(unreadable)); + } + [Fact] public void Zip_Deflate_Streamed2_ArchiveStreamRead() => ArchiveStreamRead("Zip.deflate.dd-.zip");